1 /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- 2 Copyright (c) 2012 Marcus Geelnard 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any damages 6 arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any purpose, 9 including commercial applications, and to alter it and redistribute it 10 freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not 13 claim that you wrote the original software. If you use this software 14 in a product, an acknowledgment in the product documentation would be 15 appreciated but is not required. 16 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 20 3. This notice may not be removed or altered from any source 21 distribution. 22 */ 23 24 #ifndef _TINYCTHREAD_H_ 25 #define _TINYCTHREAD_H_ 26 27 /** 28 * @file 29 * @mainpage TinyCThread API Reference 30 * 31 * @section intro_sec Introduction 32 * TinyCThread is a minimal, portable implementation of basic threading 33 * classes for C. 34 * 35 * They closely mimic the functionality and naming of the C11 standard, and 36 * should be easily replaceable with the corresponding standard variants. 37 * 38 * @section port_sec Portability 39 * The Win32 variant uses the native Win32 API for implementing the thread 40 * classes, while for other systems, the POSIX threads API (pthread) is used. 41 * 42 * @section misc_sec Miscellaneous 43 * The following special keywords are available: #_Thread_local. 44 * 45 * For more detailed information, browse the different sections of this 46 * documentation. A good place to start is: 47 * tinycthread.h. 48 */ 49 50 /* Which platform are we on? */ 51 #if !defined(_TTHREAD_PLATFORM_DEFINED_) 52 #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) 53 #define _TTHREAD_WIN32_ 54 #else 55 #define _TTHREAD_POSIX_ 56 #endif 57 #define _TTHREAD_PLATFORM_DEFINED_ 58 #endif 59 60 /* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ 61 #if defined(_TTHREAD_POSIX_) 62 #undef _FEATURES_H 63 #if !defined(_GNU_SOURCE) 64 #define _GNU_SOURCE 65 #endif 66 #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) 67 #undef _POSIX_C_SOURCE 68 #define _POSIX_C_SOURCE 199309L 69 #endif 70 #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) 71 #undef _XOPEN_SOURCE 72 #define _XOPEN_SOURCE 500 73 #endif 74 #endif 75 76 /* Generic includes */ 77 #include <time.h> 78 79 /* Platform specific includes */ 80 #if defined(_TTHREAD_POSIX_) 81 #include <sys/time.h> 82 #include <pthread.h> 83 #elif defined(_TTHREAD_WIN32_) 84 #ifndef WIN32_LEAN_AND_MEAN 85 #define WIN32_LEAN_AND_MEAN 86 #define __UNDEF_LEAN_AND_MEAN 87 #endif 88 #include <windows.h> 89 #ifdef __UNDEF_LEAN_AND_MEAN 90 #undef WIN32_LEAN_AND_MEAN 91 #undef __UNDEF_LEAN_AND_MEAN 92 #endif 93 #endif 94 95 /* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, 96 it's quite likely that libc does not support it either. Hence, fall back to 97 the only other supported time specifier: CLOCK_REALTIME (and if that fails, 98 we're probably emulating clock_gettime anyway, so anything goes). */ 99 #ifndef TIME_UTC 100 #ifdef CLOCK_REALTIME 101 #define TIME_UTC CLOCK_REALTIME 102 #else 103 #define TIME_UTC 0 104 #endif 105 #endif 106 107 /* Workaround for missing clock_gettime (most Windows compilers, afaik) */ 108 #if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__) 109 #define _TTHREAD_EMULATE_CLOCK_GETTIME_ 110 /* Emulate struct timespec */ 111 #if defined(_TTHREAD_WIN32_) 112 struct _ttherad_timespec { 113 time_t tv_sec; 114 long tv_nsec; 115 }; 116 #define timespec _ttherad_timespec 117 #endif 118 119 /* Emulate clockid_t */ 120 typedef int _tthread_clockid_t; 121 #define clockid_t _tthread_clockid_t 122 123 /* Emulate clock_gettime */ 124 int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); 125 #define clock_gettime _tthread_clock_gettime 126 #define CLOCK_REALTIME 0 127 #endif 128 129 130 /** TinyCThread version (major number). */ 131 #define TINYCTHREAD_VERSION_MAJOR 1 132 /** TinyCThread version (minor number). */ 133 #define TINYCTHREAD_VERSION_MINOR 1 134 /** TinyCThread version (full version). */ 135 #define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) 136 137 /** 138 * @def _Thread_local 139 * Thread local storage keyword. 140 * A variable that is declared with the @c _Thread_local keyword makes the 141 * value of the variable local to each thread (known as thread-local storage, 142 * or TLS). Example usage: 143 * @code 144 * // This variable is local to each thread. 145 * _Thread_local int variable; 146 * @endcode 147 * @note The @c _Thread_local keyword is a macro that maps to the corresponding 148 * compiler directive (e.g. @c __declspec(thread)). 149 * @note This directive is currently not supported on Mac OS X (it will give 150 * a compiler error), since compile-time TLS is not supported in the Mac OS X 151 * executable format. Also, some older versions of MinGW (before GCC 4.x) do 152 * not support this directive. 153 * @hideinitializer 154 */ 155 156 /* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ 157 #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) 158 #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) 159 #define _Thread_local __thread 160 #else 161 #define _Thread_local __declspec(thread) 162 #endif 163 #endif 164 165 /* Macros */ 166 #define TSS_DTOR_ITERATIONS 0 167 168 /* Function return values */ 169 #define thrd_error 0 /**< The requested operation failed */ 170 #define thrd_success 1 /**< The requested operation succeeded */ 171 #define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ 172 #define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ 173 #define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ 174 175 /* Mutex types */ 176 #define mtx_plain 1 177 #define mtx_timed 2 178 #define mtx_try 4 179 #define mtx_recursive 8 180 181 /* Mutex */ 182 #if defined(_TTHREAD_WIN32_) 183 typedef struct { 184 CRITICAL_SECTION mHandle; /* Critical section handle */ 185 int mAlreadyLocked; /* TRUE if the mutex is already locked */ 186 int mRecursive; /* TRUE if the mutex is recursive */ 187 } mtx_t; 188 #else 189 typedef pthread_mutex_t mtx_t; 190 #endif 191 192 /** Create a mutex object. 193 * @param mtx A mutex object. 194 * @param type Bit-mask that must have one of the following six values: 195 * @li @c mtx_plain for a simple non-recursive mutex 196 * @li @c mtx_timed for a non-recursive mutex that supports timeout 197 * @li @c mtx_try for a non-recursive mutex that supports test and return 198 * @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) 199 * @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) 200 * @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) 201 * @return @ref thrd_success on success, or @ref thrd_error if the request could 202 * not be honored. 203 */ 204 int mtx_init(mtx_t *mtx, int type); 205 206 /** Release any resources used by the given mutex. 207 * @param mtx A mutex object. 208 */ 209 void mtx_destroy(mtx_t *mtx); 210 211 /** Lock the given mutex. 212 * Blocks until the given mutex can be locked. If the mutex is non-recursive, and 213 * the calling thread already has a lock on the mutex, this call will block 214 * forever. 215 * @param mtx A mutex object. 216 * @return @ref thrd_success on success, or @ref thrd_error if the request could 217 * not be honored. 218 */ 219 int mtx_lock(mtx_t *mtx); 220 221 /** NOT YET IMPLEMENTED. 222 */ 223 int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); 224 225 /** Try to lock the given mutex. 226 * The specified mutex shall support either test and return or timeout. If the 227 * mutex is already locked, the function returns without blocking. 228 * @param mtx A mutex object. 229 * @return @ref thrd_success on success, or @ref thrd_busy if the resource 230 * requested is already in use, or @ref thrd_error if the request could not be 231 * honored. 232 */ 233 int mtx_trylock(mtx_t *mtx); 234 235 /** Unlock the given mutex. 236 * @param mtx A mutex object. 237 * @return @ref thrd_success on success, or @ref thrd_error if the request could 238 * not be honored. 239 */ 240 int mtx_unlock(mtx_t *mtx); 241 242 /* Condition variable */ 243 #if defined(_TTHREAD_WIN32_) 244 typedef struct { 245 HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ 246 unsigned int mWaitersCount; /* Count of the number of waiters. */ 247 CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ 248 } cnd_t; 249 #else 250 typedef pthread_cond_t cnd_t; 251 #endif 252 253 /** Create a condition variable object. 254 * @param cond A condition variable object. 255 * @return @ref thrd_success on success, or @ref thrd_error if the request could 256 * not be honored. 257 */ 258 int cnd_init(cnd_t *cond); 259 260 /** Release any resources used by the given condition variable. 261 * @param cond A condition variable object. 262 */ 263 void cnd_destroy(cnd_t *cond); 264 265 /** Signal a condition variable. 266 * Unblocks one of the threads that are blocked on the given condition variable 267 * at the time of the call. If no threads are blocked on the condition variable 268 * at the time of the call, the function does nothing and return success. 269 * @param cond A condition variable object. 270 * @return @ref thrd_success on success, or @ref thrd_error if the request could 271 * not be honored. 272 */ 273 int cnd_signal(cnd_t *cond); 274 275 /** Broadcast a condition variable. 276 * Unblocks all of the threads that are blocked on the given condition variable 277 * at the time of the call. If no threads are blocked on the condition variable 278 * at the time of the call, the function does nothing and return success. 279 * @param cond A condition variable object. 280 * @return @ref thrd_success on success, or @ref thrd_error if the request could 281 * not be honored. 282 */ 283 int cnd_broadcast(cnd_t *cond); 284 285 /** Wait for a condition variable to become signaled. 286 * The function atomically unlocks the given mutex and endeavors to block until 287 * the given condition variable is signaled by a call to cnd_signal or to 288 * cnd_broadcast. When the calling thread becomes unblocked it locks the mutex 289 * before it returns. 290 * @param cond A condition variable object. 291 * @param mtx A mutex object. 292 * @return @ref thrd_success on success, or @ref thrd_error if the request could 293 * not be honored. 294 */ 295 int cnd_wait(cnd_t *cond, mtx_t *mtx); 296 297 /** Wait for a condition variable to become signaled. 298 * The function atomically unlocks the given mutex and endeavors to block until 299 * the given condition variable is signaled by a call to cnd_signal or to 300 * cnd_broadcast, or until after the specified time. When the calling thread 301 * becomes unblocked it locks the mutex before it returns. 302 * @param cond A condition variable object. 303 * @param mtx A mutex object. 304 * @param xt A point in time at which the request will time out (absolute time). 305 * @return @ref thrd_success upon success, or @ref thrd_timeout if the time 306 * specified in the call was reached without acquiring the requested resource, or 307 * @ref thrd_error if the request could not be honored. 308 */ 309 int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); 310 311 /* Thread */ 312 #if defined(_TTHREAD_WIN32_) 313 typedef HANDLE thrd_t; 314 #else 315 typedef pthread_t thrd_t; 316 #endif 317 318 /** Thread start function. 319 * Any thread that is started with the @ref thrd_create() function must be 320 * started through a function of this type. 321 * @param arg The thread argument (the @c arg argument of the corresponding 322 * @ref thrd_create() call). 323 * @return The thread return value, which can be obtained by another thread 324 * by using the @ref thrd_join() function. 325 */ 326 typedef int (*thrd_start_t)(void *arg); 327 328 /** Create a new thread. 329 * @param thr Identifier of the newly created thread. 330 * @param func A function pointer to the function that will be executed in 331 * the new thread. 332 * @param arg An argument to the thread function. 333 * @return @ref thrd_success on success, or @ref thrd_nomem if no memory could 334 * be allocated for the thread requested, or @ref thrd_error if the request 335 * could not be honored. 336 * @note A thread’s identifier may be reused for a different thread once the 337 * original thread has exited and either been detached or joined to another 338 * thread. 339 */ 340 int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); 341 342 /** Identify the calling thread. 343 * @return The identifier of the calling thread. 344 */ 345 thrd_t thrd_current(void); 346 347 /** NOT YET IMPLEMENTED. 348 */ 349 int thrd_detach(thrd_t thr); 350 351 /** Compare two thread identifiers. 352 * The function determines if two thread identifiers refer to the same thread. 353 * @return Zero if the two thread identifiers refer to different threads. 354 * Otherwise a nonzero value is returned. 355 */ 356 int thrd_equal(thrd_t thr0, thrd_t thr1); 357 358 /** Terminate execution of the calling thread. 359 * @param res Result code of the calling thread. 360 */ 361 void thrd_exit(int res); 362 363 /** Wait for a thread to terminate. 364 * The function joins the given thread with the current thread by blocking 365 * until the other thread has terminated. 366 * @param thr The thread to join with. 367 * @param res If this pointer is not NULL, the function will store the result 368 * code of the given thread in the integer pointed to by @c res. 369 * @return @ref thrd_success on success, or @ref thrd_error if the request could 370 * not be honored. 371 */ 372 int thrd_join(thrd_t thr, int *res); 373 374 /** Put the calling thread to sleep. 375 * Suspend execution of the calling thread. 376 * @param time_point A point in time at which the thread will resume (absolute time). 377 * @param remaining If non-NULL, this parameter will hold the remaining time until 378 * time_point upon return. This will typically be zero, but if 379 * the thread was woken up by a signal that is not ignored before 380 * time_point was reached @c remaining will hold a positive 381 * time. 382 * @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. 383 */ 384 int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); 385 386 /** Yield execution to another thread. 387 * Permit other threads to run, even if the current thread would ordinarily 388 * continue to run. 389 */ 390 void thrd_yield(void); 391 392 /* Thread local storage */ 393 #if defined(_TTHREAD_WIN32_) 394 typedef DWORD tss_t; 395 #else 396 typedef pthread_key_t tss_t; 397 #endif 398 399 /** Destructor function for a thread-specific storage. 400 * @param val The value of the destructed thread-specific storage. 401 */ 402 typedef void (*tss_dtor_t)(void *val); 403 404 /** Create a thread-specific storage. 405 * @param key The unique key identifier that will be set if the function is 406 * successful. 407 * @param dtor Destructor function. This can be NULL. 408 * @return @ref thrd_success on success, or @ref thrd_error if the request could 409 * not be honored. 410 * @note The destructor function is not supported under Windows. If @c dtor is 411 * not NULL when calling this function under Windows, the function will fail 412 * and return @ref thrd_error. 413 */ 414 int tss_create(tss_t *key, tss_dtor_t dtor); 415 416 /** Delete a thread-specific storage. 417 * The function releases any resources used by the given thread-specific 418 * storage. 419 * @param key The key that shall be deleted. 420 */ 421 void tss_delete(tss_t key); 422 423 /** Get the value for a thread-specific storage. 424 * @param key The thread-specific storage identifier. 425 * @return The value for the current thread held in the given thread-specific 426 * storage. 427 */ 428 void *tss_get(tss_t key); 429 430 /** Set the value for a thread-specific storage. 431 * @param key The thread-specific storage identifier. 432 * @param val The value of the thread-specific storage to set for the current 433 * thread. 434 * @return @ref thrd_success on success, or @ref thrd_error if the request could 435 * not be honored. 436 */ 437 int tss_set(tss_t key, void *val); 438 439 440 #endif /* _TINYTHREAD_H_ */ 441 442