Blame source/uds/threadsLinuxKernel.c

Packit Service 310c69
/*
Packit Service 310c69
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service 310c69
 *
Packit Service 310c69
 * This program is free software; you can redistribute it and/or
Packit Service 310c69
 * modify it under the terms of the GNU General Public License
Packit Service 310c69
 * as published by the Free Software Foundation; either version 2
Packit Service 310c69
 * of the License, or (at your option) any later version.
Packit Service 310c69
 * 
Packit Service 310c69
 * This program is distributed in the hope that it will be useful,
Packit Service 310c69
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 310c69
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 310c69
 * GNU General Public License for more details.
Packit Service 310c69
 * 
Packit Service 310c69
 * You should have received a copy of the GNU General Public License
Packit Service 310c69
 * along with this program; if not, write to the Free Software
Packit Service 310c69
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 310c69
 * 02110-1301, USA. 
Packit Service 310c69
 *
Packit Service 310c69
 * $Id: //eng/uds-releases/jasper/kernelLinux/uds/threadsLinuxKernel.c#4 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include <linux/completion.h>
Packit Service 310c69
#include <linux/kthread.h>
Packit Service 310c69
#include <linux/sched.h>
Packit Service 310c69
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "threads.h"
Packit Service 310c69
#include "uds-error.h"
Packit Service 310c69
Packit Service 310c69
static struct hlist_head kernelThreadList;
Packit Service 310c69
static struct mutex kernelThreadMutex;
Packit Service 310c69
static OnceState kernelThreadOnce;
Packit Service 310c69
Packit Service 310c69
typedef struct kernelThread {
Packit Service 310c69
  void (*threadFunc)(void *);
Packit Service 310c69
  void *threadData;
Packit Service 310c69
  struct hlist_node threadLinks;
Packit Service 310c69
  struct task_struct *threadTask;
Packit Service 310c69
  struct completion threadDone;
Packit Service 310c69
} KernelThread;
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void kernelThreadInit(void)
Packit Service 310c69
{
Packit Service 310c69
  mutex_init(&kernelThreadMutex);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int threadStarter(void *arg)
Packit Service 310c69
{
Packit Service 310c69
  KernelThread *kt = arg;
Packit Service 310c69
  kt->threadTask = current;
Packit Service 310c69
  performOnce(&kernelThreadOnce, kernelThreadInit);
Packit Service 310c69
  mutex_lock(&kernelThreadMutex);
Packit Service 310c69
  hlist_add_head(&kt->threadLinks, &kernelThreadList);
Packit Service 310c69
  mutex_unlock(&kernelThreadMutex);
Packit Service 310c69
  RegisteredThread allocatingThread;
Packit Service 310c69
  registerAllocatingThread(&allocatingThread, NULL);
Packit Service 310c69
  kt->threadFunc(kt->threadData);
Packit Service 310c69
  unregisterAllocatingThread();
Packit Service 310c69
  complete(&kt->threadDone);
Packit Service 310c69
  return 0;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int createThread(void      (*threadFunc)(void *),
Packit Service 310c69
                 void       *threadData,
Packit Service 310c69
                 const char *name,
Packit Service 310c69
                 Thread     *newThread)
Packit Service 310c69
{
Packit Service 310c69
  char *nameColon = strchr(name, ':');
Packit Service 310c69
  char *myNameColon = strchr(current->comm, ':');
Packit Service 310c69
  KernelThread *kt;
Packit Service 310c69
  int result = ALLOCATE(1, KernelThread, __func__, &kt;;
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    logWarning("Error allocating memory for %s", name);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  kt->threadFunc = threadFunc;
Packit Service 310c69
  kt->threadData = threadData;
Packit Service 310c69
  init_completion(&kt->threadDone);
Packit Service 310c69
  struct task_struct *thread;
Packit Service 310c69
  /*
Packit Service 310c69
   * Start the thread, with an appropriate thread name.
Packit Service 310c69
   *
Packit Service 310c69
   * If the name supplied contains a colon character, use that name.  This
Packit Service 310c69
   * causes uds module threads to have names like "uds:callbackW" and the main
Packit Service 310c69
   * test runner thread to be named "zub:runtest".
Packit Service 310c69
   *
Packit Service 310c69
   * Otherwise if the current thread has a name containing a colon character,
Packit Service 310c69
   * prefix the name supplied with the name of the current thread up to (and
Packit Service 310c69
   * including) the colon character.  Thus when the "kvdo0:dedupeQ" thread
Packit Service 310c69
   * opens an index session, all the threads associated with that index will
Packit Service 310c69
   * have names like "kvdo0:foo".
Packit Service 310c69
   *
Packit Service 310c69
   * Otherwise just use the name supplied.  This should be a rare occurrence.
Packit Service 310c69
   */
Packit Service 310c69
  if ((nameColon == NULL) && (myNameColon != NULL)) {
Packit Service 310c69
    thread = kthread_run(threadStarter, kt, "%.*s:%s",
Packit Service 310c69
                         (int) (myNameColon - current->comm), current->comm,
Packit Service 310c69
                         name);
Packit Service 310c69
  } else {
Packit Service 310c69
    thread = kthread_run(threadStarter, kt, "%s", name);
Packit Service 310c69
  }
Packit Service 310c69
  if (IS_ERR(thread)) {
Packit Service 310c69
    FREE(kt);
Packit Service 310c69
    return UDS_ENOTHREADS;
Packit Service 310c69
  }
Packit Service 310c69
  *newThread = kt;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int joinThreads(Thread kt)
Packit Service 310c69
{
Packit Service 310c69
  while (wait_for_completion_interruptible(&kt->threadDone) != 0) {
Packit Service 310c69
  }
Packit Service 310c69
  mutex_lock(&kernelThreadMutex);
Packit Service 310c69
  hlist_del(&kt->threadLinks);
Packit Service 310c69
  mutex_unlock(&kernelThreadMutex);
Packit Service 310c69
  FREE(kt);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void applyToThreads(void applyFunc(void *, struct task_struct *),
Packit Service 310c69
                    void *argument)
Packit Service 310c69
{
Packit Service 310c69
  KernelThread *kt;
Packit Service 310c69
  performOnce(&kernelThreadOnce, kernelThreadInit);
Packit Service 310c69
  mutex_lock(&kernelThreadMutex);
Packit Service 310c69
  hlist_for_each_entry(kt, &kernelThreadList, threadLinks) {
Packit Service 310c69
    applyFunc(argument, kt->threadTask);
Packit Service 310c69
  }
Packit Service 310c69
  mutex_unlock(&kernelThreadMutex);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void exitThread(void)
Packit Service 310c69
{
Packit Service 310c69
  KernelThread *kt;
Packit Service 310c69
  struct completion *completion = NULL;
Packit Service 310c69
  performOnce(&kernelThreadOnce, kernelThreadInit);
Packit Service 310c69
  mutex_lock(&kernelThreadMutex);
Packit Service 310c69
  hlist_for_each_entry(kt, &kernelThreadList, threadLinks) {
Packit Service 310c69
    if (kt->threadTask == current) {
Packit Service 310c69
      completion = &kt->threadDone;
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  mutex_unlock(&kernelThreadMutex);
Packit Service 310c69
  unregisterAllocatingThread();
Packit Service 310c69
  complete_and_exit(completion, 1);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
ThreadId getThreadId(void)
Packit Service 310c69
{
Packit Service 310c69
  return current->pid;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
unsigned int getNumCores(void)
Packit Service 310c69
{
Packit Service 310c69
  return num_online_cpus();
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int initializeBarrier(Barrier *barrier, unsigned int threadCount)
Packit Service 310c69
{
Packit Service 310c69
  barrier->arrived     = 0;
Packit Service 310c69
  barrier->threadCount = threadCount;
Packit Service 310c69
  int result = initializeSemaphore(&barrier->mutex, 1);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return initializeSemaphore(&barrier->wait, 0);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int destroyBarrier(Barrier *barrier)
Packit Service 310c69
{
Packit Service 310c69
  int result = destroySemaphore(&barrier->mutex);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  return destroySemaphore(&barrier->wait);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int enterBarrier(Barrier *barrier, bool *winner)
Packit Service 310c69
{
Packit Service 310c69
  acquireSemaphore(&barrier->mutex);
Packit Service 310c69
  bool lastThread = ++barrier->arrived == barrier->threadCount;
Packit Service 310c69
  if (lastThread) {
Packit Service 310c69
    // This is the last thread to arrive, so wake up the others
Packit Service 310c69
    int i;
Packit Service 310c69
    for (i = 1; i < barrier->threadCount; i++) {
Packit Service 310c69
      releaseSemaphore(&barrier->wait);
Packit Service 310c69
    }
Packit Service 310c69
    // Then reinitialize for the next cycle
Packit Service 310c69
    barrier->arrived = 0;
Packit Service 310c69
    releaseSemaphore(&barrier->mutex);
Packit Service 310c69
  } else {
Packit Service 310c69
    // This is NOT the last thread to arrive, so just wait
Packit Service 310c69
    releaseSemaphore(&barrier->mutex);
Packit Service 310c69
    acquireSemaphore(&barrier->wait);
Packit Service 310c69
  }
Packit Service 310c69
  if (winner != NULL) {
Packit Service 310c69
    *winner = lastThread;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int yieldScheduler(void)
Packit Service 310c69
{
Packit Service 310c69
  yield();
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}