/** * \file thread.h * A collection of thread methods. */ #ifndef THREAD_H #define THREAD_H #include "timespec.h" #if HAVE_PTHREAD #include /** * Opaque type defining an once variable. */ typedef pthread_once_t thread_once_t; /** * Init value for an once variable */ #define THREAD_ONCE_INIT PTHREAD_ONCE_INIT #else # error missing thread_once_t implementation #endif /** * Opaque type defining a joinable thread. */ typedef struct thread_t thread_t; /** * Opaque type defining an id. */ typedef struct thread_id_t thread_id_t; /** * Opaque type defining a lock. */ typedef struct thread_lock_t thread_lock_t; /** * Opaque type defining a conditional. */ typedef struct thread_cond_t thread_cond_t; /** * Opaque type defining a thread local variable. */ typedef struct thread_data_t thread_data_t; /** * Signature or function type for a thread run method. * A thread run method is the thread main() if you will. * When the method returns the thread is terminated. * @param userdata argument given when starting the thread */ typedef void* (* thread_run_t)(void* userdata); /** * Create and start a thread. * @param run thread run method * @param userdata argument to run method, may not be NULL * @return true if thread was started without errors, may be NULL */ NONULL_ARGS(1) bool thread_new(thread_run_t run, void* userdata); /** * Create and start a joinable thread. * Must call thread_join to free thread resources. * @param run thread run method, may not be NULL * @param userdata argument to run method, may be NULL * @return NULL in case of error */ NONULL_ARGS(1) MALLOC thread_t* thread_joinable_new(thread_run_t run, void* userdata); /** * Wait for a joinable thread to exit, free it and return the result. * @param thread result from call to thread_joinable_new, may not be NULL * @return result of the thread run method */ NONULL void* thread_join(thread_t* thread); /** * Create a unique thread id pointing to the given or current thread. * If no thread is given then a id for the current running thread is returned. * Returns NULL in case of error. * @param thread result from call to thread_joinable_new or NULL * @return a new thread id */ MALLOC thread_id_t* thread_id_new(thread_t* thread); /** * Free a thread id. * @param id thread id to free, may be NULL */ void thread_id_free(thread_id_t* id); /** * Return true if the current thread matches the thread id. * @param id thread id to check, may not be NULL * @return true if the id matches the current thread */ NONULL bool thread_id_is_current(thread_id_t* id); /** * Thread yield, give another thread the chance to run. */ void thread_yield(void); /** * Create a possibly non-recursive lock (mutex). * Returns NULL in case of error. * @return a new thread lock */ MALLOC thread_lock_t* thread_lock_new(void); /** * Create a recursive lock (mutex). * Returns NULL in case of error. * @return a new thread lock */ MALLOC thread_lock_t* thread_lock_recursive_new(void); /** * Free a lock. * The lock must not have a owner when freed or undefined behaviour will ensue. * @param lock lock to free, may be NULL */ void thread_lock_free(thread_lock_t* lock); /** * Take ownership of the lock. * If another thread has ownership of the lock, wait until that thread releases * the lock. * If the current thread already has ownership of the lock and the lock is * recursive the current thread now owns the lock twice. * Undefined behavior (abort or deadlock probably) if the lock isn't recursive * and the current thread already has ownership. * @param lock lock to take ownership of */ NONULL void thread_lock_lock(thread_lock_t* lock); /** * Release ownership of the lock. * Only call if the current thread has one or more ownerships of the lock. * If the lock is recursive only one ownership is released. * Undefined behaviour (abort or deadlock probably) if the lock isn't owned * by the current thread. * @param lock lock to release */ NONULL void thread_lock_unlock(thread_lock_t* lock); /** * Create a conditional. Conditionals can be used to signal other threads * that a condition has been fulfilled if they were waiting for it. * Returns NULL in case of error. * @return new conditional */ MALLOC thread_cond_t* thread_cond_new(void); /** * Free a conditional. No thread may be waiting on the conditional or undefined * behaviour will ensue. * @param cond conditional to free, may be NULL */ void thread_cond_free(thread_cond_t* cond); /** * Setup the current thread to wait for the condition to be signalled. * The lock must be owned by the current thread before calling and will be * release while the current thread is waiting but reclaimed upon return. * @param cond conditonal to wait upon, may not be NULL * @param lock lock to release and retake ownership of, may not be NULL */ NONULL void thread_cond_wait(thread_cond_t* cond, thread_lock_t* lock); /** * Setup the current thread to wait for the condition to be signalled until * abstime. * The lock must be owned by the current thread before calling and will be * release while the current thread is waiting but reclaimed upon return. * Use thread_abstime() to fill out the abstime. * @param cond conditonal to wait upon, may not be NULL * @param lock lock to release and retake ownership of, may not be NULL * @param abstime time when to give up and return, may not be NULL * @return true if the condition was signalled, false if it timed out */ NONULL bool thread_cond_timedwait(thread_cond_t* cond, thread_lock_t* lock, const struct timespec *abstime); /** * Signal one thread that is currently waiting on the given condition. * The selected thread (which one is random) will be woken up. * The calling thread may or may not own the lock when calling * thread_cond_signal but the signalled thread will not wake up before the lock * is released. * @param cond conditional to signal, may not be NULL */ NONULL void thread_cond_signal(thread_cond_t* cond); /** * Signal all threads that is currently waiting on the given condition. * All waiting threads will be woken up but only one may get ownership * of the lock. * The calling thread may or may not own the lock when calling * thread_cond_broadcast but the signalled threads will not wake up before the * lock is released. * @param cond conditional to signal, may not be NULL */ NONULL void thread_cond_broadcast(thread_cond_t* cond); /** * Get the current absolute time and add a certain number of milliseconds * to it. To be used with thread_cond_timedwait. * @param abstime struct to file with the current absolute time and the * extra milliseconds. * @param add_ms milliseconds to add to the current absolute time */ NONULL void thread_abstime(struct timespec *abstime, unsigned long add_ms); /** * Function type for a thread local variable value destructor */ typedef void (* thread_data_value_free_t)(void *value); /** * Create a thread local variable. * Returns NULL in case of error. * @param free_value destructor for set non-null value at thread exit, * may be NULL * @return new thread local variable or NULL */ MALLOC thread_data_t *thread_data_new(thread_data_value_free_t free_value); /** * Free a thread local variable. * Does not call any destructor. * @param data thread local variable to free, may be NULL */ void thread_data_free(thread_data_t *data); /** * Get the thread local value of the variable. * @param data thread local variable, may not be NULL * @return thread local value for variable */ NONULL void *thread_data_value(thread_data_t *data); /** * Set thread local value for variable. * @param data thread local variable, may not be NULL * @param value new value, may be NULL */ NONULL_ARGS(1) void thread_data_set(thread_data_t *data, void *value); /** * Function type for a thread once method */ typedef void (* thread_run_once_t)(void); /** * The first thread calling this method will run "run". Any subsequent thread * calling thread_once for the same once variable will do nothing. * @param once address to a static once variable, may not be NULL * @param run method to run if this is the first thread, may not be NULL */ NONULL void thread_once(thread_once_t *once, thread_run_once_t run); #endif /* THREAD_H */