You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
443 lines
15 KiB
443 lines
15 KiB
/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- |
|
Copyright (c) 2012 Marcus Geelnard |
|
|
|
This software is provided 'as-is', without any express or implied |
|
warranty. In no event will the authors be held liable for any damages |
|
arising from the use of this software. |
|
|
|
Permission is granted to anyone to use this software for any purpose, |
|
including commercial applications, and to alter it and redistribute it |
|
freely, subject to the following restrictions: |
|
|
|
1. The origin of this software must not be misrepresented; you must not |
|
claim that you wrote the original software. If you use this software |
|
in a product, an acknowledgment in the product documentation would be |
|
appreciated but is not required. |
|
|
|
2. Altered source versions must be plainly marked as such, and must not be |
|
misrepresented as being the original software. |
|
|
|
3. This notice may not be removed or altered from any source |
|
distribution. |
|
*/ |
|
|
|
#ifndef _TINYCTHREAD_H_ |
|
#define _TINYCTHREAD_H_ |
|
|
|
/** |
|
* @file |
|
* @mainpage TinyCThread API Reference |
|
* |
|
* @section intro_sec Introduction |
|
* TinyCThread is a minimal, portable implementation of basic threading |
|
* classes for C. |
|
* |
|
* They closely mimic the functionality and naming of the C11 standard, and |
|
* should be easily replaceable with the corresponding standard variants. |
|
* |
|
* @section port_sec Portability |
|
* The Win32 variant uses the native Win32 API for implementing the thread |
|
* classes, while for other systems, the POSIX threads API (pthread) is used. |
|
* |
|
* @section misc_sec Miscellaneous |
|
* The following special keywords are available: #_Thread_local. |
|
* |
|
* For more detailed information, browse the different sections of this |
|
* documentation. A good place to start is: |
|
* tinycthread.h. |
|
*/ |
|
|
|
/* Which platform are we on? */ |
|
#if !defined(_TTHREAD_PLATFORM_DEFINED_) |
|
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) |
|
#define _TTHREAD_WIN32_ |
|
#else |
|
#define _TTHREAD_POSIX_ |
|
#endif |
|
#define _TTHREAD_PLATFORM_DEFINED_ |
|
#endif |
|
|
|
/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ |
|
#if defined(_TTHREAD_POSIX_) |
|
#undef _FEATURES_H |
|
#if !defined(_GNU_SOURCE) |
|
#define _GNU_SOURCE |
|
#endif |
|
#if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) |
|
#undef _POSIX_C_SOURCE |
|
#define _POSIX_C_SOURCE 199309L |
|
#endif |
|
#if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) |
|
#undef _XOPEN_SOURCE |
|
#define _XOPEN_SOURCE 500 |
|
#endif |
|
#endif |
|
|
|
/* Generic includes */ |
|
#include <time.h> |
|
|
|
/* Platform specific includes */ |
|
#if defined(_TTHREAD_POSIX_) |
|
#include <sys/time.h> |
|
#include <pthread.h> |
|
#elif defined(_TTHREAD_WIN32_) |
|
#ifndef WIN32_LEAN_AND_MEAN |
|
#define WIN32_LEAN_AND_MEAN |
|
#define __UNDEF_LEAN_AND_MEAN |
|
#endif |
|
#include <windows.h> |
|
#ifdef __UNDEF_LEAN_AND_MEAN |
|
#undef WIN32_LEAN_AND_MEAN |
|
#undef __UNDEF_LEAN_AND_MEAN |
|
#endif |
|
#endif |
|
|
|
/* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, |
|
it's quite likely that libc does not support it either. Hence, fall back to |
|
the only other supported time specifier: CLOCK_REALTIME (and if that fails, |
|
we're probably emulating clock_gettime anyway, so anything goes). */ |
|
#ifndef TIME_UTC |
|
#ifdef CLOCK_REALTIME |
|
#define TIME_UTC CLOCK_REALTIME |
|
#else |
|
#define TIME_UTC 0 |
|
#endif |
|
#endif |
|
|
|
/* Workaround for missing clock_gettime (most Windows compilers, afaik) */ |
|
#if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__) |
|
#define _TTHREAD_EMULATE_CLOCK_GETTIME_ |
|
/* Emulate struct timespec */ |
|
#if defined(_TTHREAD_WIN32_) |
|
struct _ttherad_timespec { |
|
time_t tv_sec; |
|
long tv_nsec; |
|
}; |
|
#define timespec _ttherad_timespec |
|
#endif |
|
|
|
/* Emulate clockid_t */ |
|
typedef int _tthread_clockid_t; |
|
#define clockid_t _tthread_clockid_t |
|
|
|
/* Emulate clock_gettime */ |
|
int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); |
|
#define clock_gettime _tthread_clock_gettime |
|
#ifndef CLOCK_REALTIME |
|
#define CLOCK_REALTIME 0 |
|
#endif |
|
#endif |
|
|
|
|
|
/** TinyCThread version (major number). */ |
|
#define TINYCTHREAD_VERSION_MAJOR 1 |
|
/** TinyCThread version (minor number). */ |
|
#define TINYCTHREAD_VERSION_MINOR 1 |
|
/** TinyCThread version (full version). */ |
|
#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) |
|
|
|
/** |
|
* @def _Thread_local |
|
* Thread local storage keyword. |
|
* A variable that is declared with the @c _Thread_local keyword makes the |
|
* value of the variable local to each thread (known as thread-local storage, |
|
* or TLS). Example usage: |
|
* @code |
|
* // This variable is local to each thread. |
|
* _Thread_local int variable; |
|
* @endcode |
|
* @note The @c _Thread_local keyword is a macro that maps to the corresponding |
|
* compiler directive (e.g. @c __declspec(thread)). |
|
* @note This directive is currently not supported on Mac OS X (it will give |
|
* a compiler error), since compile-time TLS is not supported in the Mac OS X |
|
* executable format. Also, some older versions of MinGW (before GCC 4.x) do |
|
* not support this directive. |
|
* @hideinitializer |
|
*/ |
|
|
|
/* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ |
|
#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) |
|
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) |
|
#define _Thread_local __thread |
|
#else |
|
#define _Thread_local __declspec(thread) |
|
#endif |
|
#endif |
|
|
|
/* Macros */ |
|
#define TSS_DTOR_ITERATIONS 0 |
|
|
|
/* Function return values */ |
|
#define thrd_error 0 /**< The requested operation failed */ |
|
#define thrd_success 1 /**< The requested operation succeeded */ |
|
#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ |
|
#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ |
|
#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ |
|
|
|
/* Mutex types */ |
|
#define mtx_plain 1 |
|
#define mtx_timed 2 |
|
#define mtx_try 4 |
|
#define mtx_recursive 8 |
|
|
|
/* Mutex */ |
|
#if defined(_TTHREAD_WIN32_) |
|
typedef struct { |
|
CRITICAL_SECTION mHandle; /* Critical section handle */ |
|
int mAlreadyLocked; /* TRUE if the mutex is already locked */ |
|
int mRecursive; /* TRUE if the mutex is recursive */ |
|
} mtx_t; |
|
#else |
|
typedef pthread_mutex_t mtx_t; |
|
#endif |
|
|
|
/** Create a mutex object. |
|
* @param mtx A mutex object. |
|
* @param type Bit-mask that must have one of the following six values: |
|
* @li @c mtx_plain for a simple non-recursive mutex |
|
* @li @c mtx_timed for a non-recursive mutex that supports timeout |
|
* @li @c mtx_try for a non-recursive mutex that supports test and return |
|
* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) |
|
* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) |
|
* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int mtx_init(mtx_t *mtx, int type); |
|
|
|
/** Release any resources used by the given mutex. |
|
* @param mtx A mutex object. |
|
*/ |
|
void mtx_destroy(mtx_t *mtx); |
|
|
|
/** Lock the given mutex. |
|
* Blocks until the given mutex can be locked. If the mutex is non-recursive, and |
|
* the calling thread already has a lock on the mutex, this call will block |
|
* forever. |
|
* @param mtx A mutex object. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int mtx_lock(mtx_t *mtx); |
|
|
|
/** NOT YET IMPLEMENTED. |
|
*/ |
|
int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); |
|
|
|
/** Try to lock the given mutex. |
|
* The specified mutex shall support either test and return or timeout. If the |
|
* mutex is already locked, the function returns without blocking. |
|
* @param mtx A mutex object. |
|
* @return @ref thrd_success on success, or @ref thrd_busy if the resource |
|
* requested is already in use, or @ref thrd_error if the request could not be |
|
* honored. |
|
*/ |
|
int mtx_trylock(mtx_t *mtx); |
|
|
|
/** Unlock the given mutex. |
|
* @param mtx A mutex object. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int mtx_unlock(mtx_t *mtx); |
|
|
|
/* Condition variable */ |
|
#if defined(_TTHREAD_WIN32_) |
|
typedef struct { |
|
HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ |
|
unsigned int mWaitersCount; /* Count of the number of waiters. */ |
|
CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ |
|
} cnd_t; |
|
#else |
|
typedef pthread_cond_t cnd_t; |
|
#endif |
|
|
|
/** Create a condition variable object. |
|
* @param cond A condition variable object. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int cnd_init(cnd_t *cond); |
|
|
|
/** Release any resources used by the given condition variable. |
|
* @param cond A condition variable object. |
|
*/ |
|
void cnd_destroy(cnd_t *cond); |
|
|
|
/** Signal a condition variable. |
|
* Unblocks one of the threads that are blocked on the given condition variable |
|
* at the time of the call. If no threads are blocked on the condition variable |
|
* at the time of the call, the function does nothing and return success. |
|
* @param cond A condition variable object. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int cnd_signal(cnd_t *cond); |
|
|
|
/** Broadcast a condition variable. |
|
* Unblocks all of the threads that are blocked on the given condition variable |
|
* at the time of the call. If no threads are blocked on the condition variable |
|
* at the time of the call, the function does nothing and return success. |
|
* @param cond A condition variable object. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int cnd_broadcast(cnd_t *cond); |
|
|
|
/** Wait for a condition variable to become signaled. |
|
* The function atomically unlocks the given mutex and endeavors to block until |
|
* the given condition variable is signaled by a call to cnd_signal or to |
|
* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex |
|
* before it returns. |
|
* @param cond A condition variable object. |
|
* @param mtx A mutex object. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int cnd_wait(cnd_t *cond, mtx_t *mtx); |
|
|
|
/** Wait for a condition variable to become signaled. |
|
* The function atomically unlocks the given mutex and endeavors to block until |
|
* the given condition variable is signaled by a call to cnd_signal or to |
|
* cnd_broadcast, or until after the specified time. When the calling thread |
|
* becomes unblocked it locks the mutex before it returns. |
|
* @param cond A condition variable object. |
|
* @param mtx A mutex object. |
|
* @param xt A point in time at which the request will time out (absolute time). |
|
* @return @ref thrd_success upon success, or @ref thrd_timeout if the time |
|
* specified in the call was reached without acquiring the requested resource, or |
|
* @ref thrd_error if the request could not be honored. |
|
*/ |
|
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); |
|
|
|
/* Thread */ |
|
#if defined(_TTHREAD_WIN32_) |
|
typedef HANDLE thrd_t; |
|
#else |
|
typedef pthread_t thrd_t; |
|
#endif |
|
|
|
/** Thread start function. |
|
* Any thread that is started with the @ref thrd_create() function must be |
|
* started through a function of this type. |
|
* @param arg The thread argument (the @c arg argument of the corresponding |
|
* @ref thrd_create() call). |
|
* @return The thread return value, which can be obtained by another thread |
|
* by using the @ref thrd_join() function. |
|
*/ |
|
typedef int (*thrd_start_t)(void *arg); |
|
|
|
/** Create a new thread. |
|
* @param thr Identifier of the newly created thread. |
|
* @param func A function pointer to the function that will be executed in |
|
* the new thread. |
|
* @param arg An argument to the thread function. |
|
* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could |
|
* be allocated for the thread requested, or @ref thrd_error if the request |
|
* could not be honored. |
|
* @note A thread’s identifier may be reused for a different thread once the |
|
* original thread has exited and either been detached or joined to another |
|
* thread. |
|
*/ |
|
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); |
|
|
|
/** Identify the calling thread. |
|
* @return The identifier of the calling thread. |
|
*/ |
|
thrd_t thrd_current(void); |
|
|
|
/** NOT YET IMPLEMENTED. |
|
*/ |
|
int thrd_detach(thrd_t thr); |
|
|
|
/** Compare two thread identifiers. |
|
* The function determines if two thread identifiers refer to the same thread. |
|
* @return Zero if the two thread identifiers refer to different threads. |
|
* Otherwise a nonzero value is returned. |
|
*/ |
|
int thrd_equal(thrd_t thr0, thrd_t thr1); |
|
|
|
/** Terminate execution of the calling thread. |
|
* @param res Result code of the calling thread. |
|
*/ |
|
void thrd_exit(int res); |
|
|
|
/** Wait for a thread to terminate. |
|
* The function joins the given thread with the current thread by blocking |
|
* until the other thread has terminated. |
|
* @param thr The thread to join with. |
|
* @param res If this pointer is not NULL, the function will store the result |
|
* code of the given thread in the integer pointed to by @c res. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int thrd_join(thrd_t thr, int *res); |
|
|
|
/** Put the calling thread to sleep. |
|
* Suspend execution of the calling thread. |
|
* @param time_point A point in time at which the thread will resume (absolute time). |
|
* @param remaining If non-NULL, this parameter will hold the remaining time until |
|
* time_point upon return. This will typically be zero, but if |
|
* the thread was woken up by a signal that is not ignored before |
|
* time_point was reached @c remaining will hold a positive |
|
* time. |
|
* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. |
|
*/ |
|
int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); |
|
|
|
/** Yield execution to another thread. |
|
* Permit other threads to run, even if the current thread would ordinarily |
|
* continue to run. |
|
*/ |
|
void thrd_yield(void); |
|
|
|
/* Thread local storage */ |
|
#if defined(_TTHREAD_WIN32_) |
|
typedef DWORD tss_t; |
|
#else |
|
typedef pthread_key_t tss_t; |
|
#endif |
|
|
|
/** Destructor function for a thread-specific storage. |
|
* @param val The value of the destructed thread-specific storage. |
|
*/ |
|
typedef void (*tss_dtor_t)(void *val); |
|
|
|
/** Create a thread-specific storage. |
|
* @param key The unique key identifier that will be set if the function is |
|
* successful. |
|
* @param dtor Destructor function. This can be NULL. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
* @note The destructor function is not supported under Windows. If @c dtor is |
|
* not NULL when calling this function under Windows, the function will fail |
|
* and return @ref thrd_error. |
|
*/ |
|
int tss_create(tss_t *key, tss_dtor_t dtor); |
|
|
|
/** Delete a thread-specific storage. |
|
* The function releases any resources used by the given thread-specific |
|
* storage. |
|
* @param key The key that shall be deleted. |
|
*/ |
|
void tss_delete(tss_t key); |
|
|
|
/** Get the value for a thread-specific storage. |
|
* @param key The thread-specific storage identifier. |
|
* @return The value for the current thread held in the given thread-specific |
|
* storage. |
|
*/ |
|
void *tss_get(tss_t key); |
|
|
|
/** Set the value for a thread-specific storage. |
|
* @param key The thread-specific storage identifier. |
|
* @param val The value of the thread-specific storage to set for the current |
|
* thread. |
|
* @return @ref thrd_success on success, or @ref thrd_error if the request could |
|
* not be honored. |
|
*/ |
|
int tss_set(tss_t key, void *val); |
|
|
|
|
|
#endif /* _TINYTHREAD_H_ */ |
|
|
|
|