Blame source/uds/threads.h

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/src/uds/threads.h#4 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#ifndef THREADS_H
Packit Service 310c69
#define THREADS_H
Packit Service 310c69
Packit Service 310c69
#include "compiler.h"
Packit Service 310c69
#include "threadOnce.h"
Packit Service 310c69
#include "timeUtils.h"
Packit Service 310c69
#include "uds-error.h"
Packit Service 310c69
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
#include <linux/jiffies.h>
Packit Service 310c69
#include <linux/mutex.h>
Packit Service 310c69
#include <linux/semaphore.h>
Packit Service 310c69
#include "util/eventCount.h"
Packit Service 310c69
#else
Packit Service 310c69
#include <pthread.h>
Packit Service 310c69
#include <semaphore.h>
Packit Service 310c69
#include <stdbool.h>
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
typedef struct { EventCount *eventCount; } CondVar;
Packit Service 310c69
typedef struct mutex                       Mutex;
Packit Service 310c69
typedef struct semaphore                   Semaphore;
Packit Service 310c69
typedef struct kernelThread               *Thread;
Packit Service 310c69
typedef pid_t                              ThreadId;
Packit Service 310c69
Packit Service 310c69
typedef struct {
Packit Service 310c69
  Semaphore mutex;       // Mutex for this barrier object
Packit Service 310c69
  Semaphore wait;        // Semaphore for threads waiting at the barrier
Packit Service 310c69
  int       arrived;     // Number of threads which have arrived
Packit Service 310c69
  int       threadCount; // Total number of threads using this barrier
Packit Service 310c69
} Barrier;
Packit Service 310c69
#else
Packit Service 310c69
typedef pthread_barrier_t Barrier;
Packit Service 310c69
typedef pthread_cond_t    CondVar;
Packit Service 310c69
typedef pthread_mutex_t   Mutex;
Packit Service 310c69
typedef sem_t             Semaphore;
Packit Service 310c69
typedef pthread_t         Thread;
Packit Service 310c69
typedef pid_t             ThreadId;
Packit Service 310c69
Packit Service 310c69
#ifndef NDEBUG
Packit Service 310c69
#define MUTEX_INITIALIZER PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
Packit Service 310c69
#else
Packit Service 310c69
#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
extern const bool DO_ASSERTIONS;
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
/**
Packit Service 310c69
 * Apply a function to every thread that we have created.
Packit Service 310c69
 *
Packit Service 310c69
 * @param applyFunc  The function to apply
Packit Service 310c69
 * @param argument   The first argument to applyFunc
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
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Create a thread, logging any cause of failure.
Packit Service 310c69
 *
Packit Service 310c69
 * @param threadFunc  function to run in new thread
Packit Service 310c69
 * @param threadData  private data for new thread
Packit Service 310c69
 * @param name        name of the new thread
Packit Service 310c69
 * @param newThread   where to store the new thread id
Packit Service 310c69
 *
Packit Service 310c69
 * @return       success or failure indication
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
  __attribute__((warn_unused_result));
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Retrieve the current numbers of cores.
Packit Service 310c69
 *
Packit Service 310c69
 * This is either the total number or the number of cores that this
Packit Service 310c69
 * process has been limited to.
Packit Service 310c69
 *
Packit Service 310c69
 * @return      number of cores
Packit Service 310c69
 **/
Packit Service 310c69
unsigned int getNumCores(void);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Return the id of the current thread.
Packit Service 310c69
 *
Packit Service 310c69
 * @return the thread id
Packit Service 310c69
 **/
Packit Service 310c69
ThreadId getThreadId(void) __attribute__((warn_unused_result));
Packit Service 310c69
Packit Service 310c69
#ifndef __KERNEL__
Packit Service 310c69
/**
Packit Service 310c69
 * Get the name of the current thread.
Packit Service 310c69
 *
Packit Service 310c69
 * @param name   a buffer of size at least 16 to write the name to
Packit Service 310c69
 **/
Packit Service 310c69
void getThreadName(char *name);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Wait for termination of another thread.
Packit Service 310c69
 *
Packit Service 310c69
 *
Packit Service 310c69
 * @param th             The thread for which to wait.
Packit Service 310c69
 *
Packit Service 310c69
 * @return               UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int joinThreads(Thread th);
Packit Service 310c69
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
/**
Packit Service 310c69
 * Exit the current thread.  This is a kernel-only function that is intended to
Packit Service 310c69
 * be an alternative to using BUG() or BUG_ON().
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((noreturn))
Packit Service 310c69
void exitThread(void);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Initialize a thread synchronization barrier (also known as a rendezvous).
Packit Service 310c69
 *
Packit Service 310c69
 * @param barrier      the barrier to initialize
Packit Service 310c69
 * @param threadCount  the number of threads that must enter the barrier before
Packit Service 310c69
 *                     any threads are permitted to leave it
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
int initializeBarrier(Barrier *barrier, unsigned int threadCount)
Packit Service 310c69
  __attribute__((warn_unused_result));
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Destroy a thread synchronization barrier.
Packit Service 310c69
 *
Packit Service 310c69
 * @param barrier   the barrier to destroy
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
int destroyBarrier(Barrier *barrier);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Enter a thread synchronization barrier, waiting for the configured number
Packit Service 310c69
 * of threads to have entered before exiting the barrier. Exactly one thread
Packit Service 310c69
 * will be arbitrarily selected to be flagged as the "winner" of a barrier.
Packit Service 310c69
 *
Packit Service 310c69
 * @param barrier   the barrier to enter
Packit Service 310c69
 * @param winner    if non-NULL, a pointer to the flag indicating whether the
Packit Service 310c69
 *                  calling thread was the unique winner
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
int enterBarrier(Barrier *barrier, bool *winner);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Initialize a condition variable with default attributes.
Packit Service 310c69
 *
Packit Service 310c69
 * @param cond       condition variable to init
Packit Service 310c69
 *
Packit Service 310c69
 * @return           UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int initCond(CondVar *cond) __attribute__((warn_unused_result));
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Signal a condition variable.
Packit Service 310c69
 *
Packit Service 310c69
 * @param cond  condition variable to signal
Packit Service 310c69
 *
Packit Service 310c69
 * @return      UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int signalCond(CondVar *cond);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Broadcast a condition variable.
Packit Service 310c69
 *
Packit Service 310c69
 * @param cond  condition variable to broadcast
Packit Service 310c69
 *
Packit Service 310c69
 * @return      UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int broadcastCond(CondVar *cond);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Wait on a condition variable.
Packit Service 310c69
 *
Packit Service 310c69
 * @param cond    condition variable to wait on
Packit Service 310c69
 * @param mutex   mutex to release while waiting
Packit Service 310c69
 *
Packit Service 310c69
 * @return        UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int waitCond(CondVar *cond, Mutex *mutex);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Wait on a condition variable with a timeout.
Packit Service 310c69
 *
Packit Service 310c69
 * @param cond     condition variable to wait on
Packit Service 310c69
 * @param mutex    mutex to release while waiting
Packit Service 310c69
 * @param timeout  the relative time until the timeout expires
Packit Service 310c69
 *
Packit Service 310c69
 * @return error code (ETIMEDOUT if the deadline is hit)
Packit Service 310c69
 **/
Packit Service 310c69
int timedWaitCond(CondVar *cond, Mutex *mutex, RelTime timeout);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Destroy a condition variable.
Packit Service 310c69
 *
Packit Service 310c69
 * @param cond  condition variable to destroy
Packit Service 310c69
 *
Packit Service 310c69
 * @return      UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int destroyCond(CondVar *cond);
Packit Service 310c69
Packit Service 310c69
#ifndef __KERNEL__
Packit Service 310c69
/**
Packit Service 310c69
 * Initialize a mutex, optionally asserting if the mutex initialization fails.
Packit Service 310c69
 * This function should only be called directly in places where making
Packit Service 310c69
 * assertions is not safe.
Packit Service 310c69
 *
Packit Service 310c69
 * @param mutex         the mutex to initialize
Packit Service 310c69
 * @param assertOnError if true, an error initializing the
Packit Service 310c69
 *                      mutex will make an assertion
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
int initializeMutex(Mutex *mutex, bool assertOnError);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Initialize the default type (error-checking during development) mutex.
Packit Service 310c69
 *
Packit Service 310c69
 * @param mutex the mutex to initialize
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE int initMutex(Mutex *mutex)
Packit Service 310c69
{
Packit Service 310c69
  mutex_init(mutex);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
int initMutex(Mutex *mutex);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Destroy a mutex (with error checking during development).
Packit Service 310c69
 *
Packit Service 310c69
 * @param mutex mutex to destroy
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE int destroyMutex(Mutex *mutex)
Packit Service 310c69
{
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
int destroyMutex(Mutex *mutex);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Lock a mutex, with optional error checking during development.
Packit Service 310c69
 *
Packit Service 310c69
 * @param mutex mutex to lock
Packit Service 310c69
 **/
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE void lockMutex(Mutex *mutex)
Packit Service 310c69
{
Packit Service 310c69
  mutex_lock(mutex);
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
void lockMutex(Mutex *mutex);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Unlock a mutex, with optional error checking during development.
Packit Service 310c69
 *
Packit Service 310c69
 * @param mutex mutex to unlock
Packit Service 310c69
 **/
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE void unlockMutex(Mutex *mutex)
Packit Service 310c69
{
Packit Service 310c69
  mutex_unlock(mutex);
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
void unlockMutex(Mutex *mutex);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Initialize a semaphore used among threads in the same process.
Packit Service 310c69
 *
Packit Service 310c69
 * @param semaphore the semaphore to initialize
Packit Service 310c69
 * @param value     the initial value of the semaphore
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE int initializeSemaphore(Semaphore *semaphore, unsigned int value)
Packit Service 310c69
{
Packit Service 310c69
  sema_init(semaphore, value);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
int initializeSemaphore(Semaphore *semaphore, unsigned int value);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Destroy a semaphore used among threads in the same process.
Packit Service 310c69
 *
Packit Service 310c69
 * @param semaphore the semaphore to destroy
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE int destroySemaphore(Semaphore *semaphore)
Packit Service 310c69
{
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
int destroySemaphore(Semaphore *semaphore);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Acquire a permit from a semaphore, waiting if none are currently available.
Packit Service 310c69
 *
Packit Service 310c69
 * @param semaphore the semaphore to acquire
Packit Service 310c69
 **/
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE void acquireSemaphore(Semaphore *semaphore)
Packit Service 310c69
{
Packit Service 310c69
  // Do not use down(semaphore).  Instead use down_interruptible so that we do
Packit Service 310c69
  // not get 120 second stall messages in kern.log.
Packit Service 310c69
  while (down_interruptible(semaphore) != 0) {
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
void acquireSemaphore(Semaphore *semaphore);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Attempt to acquire a permit from a semaphore.
Packit Service 310c69
 *
Packit Service 310c69
 * If a permit is available, it is claimed and the function immediately
Packit Service 310c69
 * returns true. If a timeout is zero or negative, the function immediately
Packit Service 310c69
 * returns false. Otherwise, this will wait either a permit to become
Packit Service 310c69
 * available (returning true) or the relative timeout to expire (returning
Packit Service 310c69
 * false).
Packit Service 310c69
 *
Packit Service 310c69
 * @param semaphore the semaphore to decrement
Packit Service 310c69
 * @param timeout   the relative time until the timeout expires
Packit Service 310c69
 *
Packit Service 310c69
 * @return true if a permit was acquired, otherwise false
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE bool attemptSemaphore(Semaphore *semaphore, RelTime timeout)
Packit Service 310c69
{
Packit Service 310c69
  if (timeout <= 0) {
Packit Service 310c69
    // No timeout, just try to grab the semaphore.
Packit Service 310c69
    return down_trylock(semaphore) == 0;
Packit Service 310c69
  } else {
Packit Service 310c69
    unsigned int jiffies = usecs_to_jiffies(relTimeToMicroseconds(timeout));
Packit Service 310c69
    return down_timeout(semaphore, jiffies) == 0;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
bool attemptSemaphore(Semaphore *semaphore, RelTime timeout);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Release a semaphore, incrementing the number of available permits.
Packit Service 310c69
 *
Packit Service 310c69
 * @param semaphore the semaphore to increment
Packit Service 310c69
 **/
Packit Service 310c69
#ifdef __KERNEL__
Packit Service 310c69
static INLINE void releaseSemaphore(Semaphore *semaphore)
Packit Service 310c69
{
Packit Service 310c69
  up(semaphore);
Packit Service 310c69
}
Packit Service 310c69
#else
Packit Service 310c69
void releaseSemaphore(Semaphore *semaphore);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Yield the time slice in the given thread.
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
int yieldScheduler(void);
Packit Service 310c69
Packit Service 310c69
#ifndef __KERNEL__
Packit Service 310c69
/**
Packit Service 310c69
 * Allocate a thread specific key for thread specific data.
Packit Service 310c69
 *
Packit Service 310c69
 * @param key            points to location for new key
Packit Service 310c69
 * @param destr_function destructor function called when thread exits
Packit Service 310c69
 *
Packit Service 310c69
 * @return               UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int createThreadKey(pthread_key_t *key, void (*destr_function) (void *));
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Delete a thread specific key for thread specific data.
Packit Service 310c69
 *
Packit Service 310c69
 * @param key  key to delete
Packit Service 310c69
 *
Packit Service 310c69
 * @return     UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int deleteThreadKey(pthread_key_t key);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Set pointer for thread specific data.
Packit Service 310c69
 *
Packit Service 310c69
 * @param key      key to be associated with pointer
Packit Service 310c69
 * @param pointer  data associated with key
Packit Service 310c69
 *
Packit Service 310c69
 * @return         UDS_SUCCESS or error code
Packit Service 310c69
 **/
Packit Service 310c69
int setThreadSpecific(pthread_key_t key, const void *pointer);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get pointer for thread specific data.
Packit Service 310c69
 *
Packit Service 310c69
 * @param key  key identifying the thread specific data
Packit Service 310c69
 **/
Packit Service 310c69
void *getThreadSpecific(pthread_key_t key);
Packit Service 310c69
#endif
Packit Service 310c69
Packit Service 310c69
#endif /* THREADS_H */