1 /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- 2 Copyright (c) 2012 Marcus Geelnard 3 Copyright (c) 2013-2016 Evan Nemerson 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 18 2. Altered source versions must be plainly marked as such, and must not be 19 misrepresented as being the original software. 20 21 3. This notice may not be removed or altered from any source 22 distribution. 23 */ 24 25 #ifndef _TINYCTHREAD_H_ 26 #define _TINYCTHREAD_H_ 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 #include "badthreads.h" 33 34 // jcheng 2017-11-03: _XOPEN_SOURCE 600 is necessary to prevent Solaris headers 35 // from complaining about the combination of C99 and _XOPEN_SOURCE <= 500. The 36 // error message starts with: 37 // "Compiler or options invalid for pre-UNIX 03 X/Open applications" 38 #if defined(sun) && (__STDC_VERSION__ - 0 >= 199901L) && (!defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 600)) 39 #undef _XOPEN_SOURCE 40 #define _XOPEN_SOURCE 600 41 #endif 42 43 /** 44 * @file 45 * @mainpage TinyCThread API Reference 46 * 47 * @section intro_sec Introduction 48 * TinyCThread is a minimal, portable implementation of basic threading 49 * classes for C. 50 * 51 * They closely mimic the functionality and naming of the C11 standard, and 52 * should be easily replaceable with the corresponding standard variants. 53 * 54 * @section port_sec Portability 55 * The Win32 variant uses the native Win32 API for implementing the thread 56 * classes, while for other systems, the POSIX threads API (pthread) is used. 57 * 58 * @section misc_sec Miscellaneous 59 * The following special keywords are available: #_Thread_local. 60 * 61 * For more detailed information, browse the different sections of this 62 * documentation. A good place to start is: 63 * tinycthread.h. 64 */ 65 66 /* Which platform are we on? */ 67 #if !defined(_TTHREAD_PLATFORM_DEFINED_) 68 #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) 69 #define _TTHREAD_WIN32_ 70 #else 71 #define _TTHREAD_POSIX_ 72 #endif 73 #define _TTHREAD_PLATFORM_DEFINED_ 74 #endif 75 76 /* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ 77 #if defined(_TTHREAD_POSIX_) 78 #undef _FEATURES_H 79 #if !defined(_GNU_SOURCE) 80 #define _GNU_SOURCE 81 #endif 82 #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) 83 #undef _POSIX_C_SOURCE 84 #define _POSIX_C_SOURCE 199309L 85 #endif 86 #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) 87 #undef _XOPEN_SOURCE 88 #define _XOPEN_SOURCE 500 89 #endif 90 #define _XPG6 91 #endif 92 93 /* Generic includes */ 94 #include <time.h> 95 96 /* Platform specific includes */ 97 #if defined(_TTHREAD_POSIX_) 98 #include <pthread.h> 99 #elif defined(_TTHREAD_WIN32_) 100 #ifndef WIN32_LEAN_AND_MEAN 101 #define WIN32_LEAN_AND_MEAN 102 #define __UNDEF_LEAN_AND_MEAN 103 #endif 104 #include <windows.h> 105 #ifdef __UNDEF_LEAN_AND_MEAN 106 #undef WIN32_LEAN_AND_MEAN 107 #undef __UNDEF_LEAN_AND_MEAN 108 #endif 109 #endif 110 111 /* Compiler-specific information */ 112 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L 113 #define TTHREAD_NORETURN _Noreturn 114 #elif defined(__GNUC__) 115 #define TTHREAD_NORETURN __attribute__((__noreturn__)) 116 #else 117 #define TTHREAD_NORETURN 118 #endif 119 120 /* If TIME_UTC is missing, provide it and provide a wrapper for 121 timespec_get. */ 122 #ifndef TIME_UTC 123 #define TIME_UTC 1 124 #define _TTHREAD_EMULATE_TIMESPEC_GET_ 125 126 #if defined(_TTHREAD_WIN32_) 127 struct _tthread_timespec { 128 time_t tv_sec; 129 long tv_nsec; 130 }; 131 #define timespec _tthread_timespec 132 #endif 133 134 int _tthread_timespec_get(struct timespec *ts, int base); 135 #define timespec_get _tthread_timespec_get 136 #endif 137 138 /** TinyCThread version (major number). */ 139 #define TINYCTHREAD_VERSION_MAJOR 1 140 /** TinyCThread version (minor number). */ 141 #define TINYCTHREAD_VERSION_MINOR 2 142 /** TinyCThread version (full version). */ 143 #define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) 144 145 /** 146 * @def _Thread_local 147 * Thread local storage keyword. 148 * A variable that is declared with the @c _Thread_local keyword makes the 149 * value of the variable local to each thread (known as thread-local storage, 150 * or TLS). Example usage: 151 * @code 152 * // This variable is local to each thread. 153 * _Thread_local int variable; 154 * @endcode 155 * @note The @c _Thread_local keyword is a macro that maps to the corresponding 156 * compiler directive (e.g. @c __declspec(thread)). 157 * @note This directive is currently not supported on Mac OS X (it will give 158 * a compiler error), since compile-time TLS is not supported in the Mac OS X 159 * executable format. Also, some older versions of MinGW (before GCC 4.x) do 160 * not support this directive, nor does the Tiny C Compiler. 161 * @hideinitializer 162 */ 163 164 #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) 165 #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) 166 #define _Thread_local __thread 167 #else 168 #define _Thread_local __declspec(thread) 169 #endif 170 #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && (((__GNUC__ << 8) | __GNUC_MINOR__) < ((4 << 8) | 9)) 171 #define _Thread_local __thread 172 #endif 173 174 /* Macros */ 175 #if defined(_TTHREAD_WIN32_) 176 #define TCT_TSS_DTOR_ITERATIONS (4) 177 #else 178 #define TCT_TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS 179 #endif 180 181 /* Function return values */ 182 #define tct_thrd_error 0 /**< The requested operation failed */ 183 #define tct_thrd_success 1 /**< The requested operation succeeded */ 184 #define tct_thrd_timedout 2 /**< The time specified in the call was reached without acquiring the requested resource */ 185 #define tct_thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ 186 #define tct_thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ 187 188 /* Mutex types */ 189 #define tct_mtx_plain 0 190 #define tct_mtx_timed 1 191 #define tct_mtx_recursive 2 192 193 /* Mutex */ 194 #if defined(_TTHREAD_WIN32_) 195 typedef struct { 196 union { 197 CRITICAL_SECTION cs; /* Critical section handle (used for non-timed mutexes) */ 198 HANDLE mut; /* Mutex handle (used for timed mutex) */ 199 } mHandle; /* Mutex handle */ 200 int mAlreadyLocked; /* TRUE if the mutex is already locked */ 201 int mRecursive; /* TRUE if the mutex is recursive */ 202 int mTimed; /* TRUE if the mutex is timed */ 203 } tct_mtx_t; 204 #else 205 typedef pthread_mutex_t tct_mtx_t; 206 #endif 207 208 /** Create a mutex object. 209 * @param mtx A mutex object. 210 * @param type Bit-mask that must have one of the following six values: 211 * @li @c mtx_plain for a simple non-recursive mutex 212 * @li @c mtx_timed for a non-recursive mutex that supports timeout 213 * @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) 214 * @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) 215 * @return @ref thrd_success on success, or @ref thrd_error if the request could 216 * not be honored. 217 */ 218 int tct_mtx_init(tct_mtx_t *mtx, int type); 219 220 /** Release any resources used by the given mutex. 221 * @param mtx A mutex object. 222 */ 223 void tct_mtx_destroy(tct_mtx_t *mtx); 224 225 /** Lock the given mutex. 226 * Blocks until the given mutex can be locked. If the mutex is non-recursive, and 227 * the calling thread already has a lock on the mutex, this call will block 228 * forever. 229 * @param mtx A mutex object. 230 * @return @ref thrd_success on success, or @ref thrd_error if the request could 231 * not be honored. 232 */ 233 int tct_mtx_lock(tct_mtx_t *mtx); 234 235 /** Lock the given mutex, or block until a specific point in time. 236 * Blocks until either the given mutex can be locked, or the specified TIME_UTC 237 * based time. 238 * @param mtx A mutex object. 239 * @param ts A UTC based calendar time 240 * @return @ref The mtx_timedlock function returns thrd_success on success, or 241 * thrd_timedout if the time specified was reached without acquiring the 242 * requested resource, or thrd_error if the request could not be honored. 243 */ 244 int tct_mtx_timedlock(tct_mtx_t *mtx, const struct timespec *ts); 245 246 /** Try to lock the given mutex. 247 * The specified mutex shall support either test and return or timeout. If the 248 * mutex is already locked, the function returns without blocking. 249 * @param mtx A mutex object. 250 * @return @ref thrd_success on success, or @ref thrd_busy if the resource 251 * requested is already in use, or @ref thrd_error if the request could not be 252 * honored. 253 */ 254 int tct_mtx_trylock(tct_mtx_t *mtx); 255 256 /** Unlock the given mutex. 257 * @param mtx A mutex object. 258 * @return @ref thrd_success on success, or @ref thrd_error if the request could 259 * not be honored. 260 */ 261 int tct_mtx_unlock(tct_mtx_t *mtx); 262 263 /* Condition variable */ 264 #if defined(_TTHREAD_WIN32_) 265 typedef struct { 266 HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ 267 unsigned int mWaitersCount; /* Count of the number of waiters. */ 268 CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ 269 } tct_cnd_t; 270 #else 271 typedef pthread_cond_t tct_cnd_t; 272 #endif 273 274 /** Create a condition variable object. 275 * @param cond A condition variable object. 276 * @return @ref thrd_success on success, or @ref thrd_error if the request could 277 * not be honored. 278 */ 279 int tct_cnd_init(tct_cnd_t *cond); 280 281 /** Release any resources used by the given condition variable. 282 * @param cond A condition variable object. 283 */ 284 void tct_cnd_destroy(tct_cnd_t *cond); 285 286 /** Signal a condition variable. 287 * Unblocks one of the threads that are blocked on the given condition variable 288 * at the time of the call. If no threads are blocked on the condition variable 289 * at the time of the call, the function does nothing and return success. 290 * @param cond A condition variable object. 291 * @return @ref thrd_success on success, or @ref thrd_error if the request could 292 * not be honored. 293 */ 294 int tct_cnd_signal(tct_cnd_t *cond); 295 296 /** Broadcast a condition variable. 297 * Unblocks all of the threads that are blocked on the given condition variable 298 * at the time of the call. If no threads are blocked on the condition variable 299 * at the time of the call, the function does nothing and return success. 300 * @param cond A condition variable object. 301 * @return @ref thrd_success on success, or @ref thrd_error if the request could 302 * not be honored. 303 */ 304 int tct_cnd_broadcast(tct_cnd_t *cond); 305 306 /** Wait for a condition variable to become signaled. 307 * The function atomically unlocks the given mutex and endeavors to block until 308 * the given condition variable is signaled by a call to cnd_signal or to 309 * cnd_broadcast. When the calling thread becomes unblocked it locks the mutex 310 * before it returns. 311 * @param cond A condition variable object. 312 * @param mtx A mutex object. 313 * @return @ref thrd_success on success, or @ref thrd_error if the request could 314 * not be honored. 315 */ 316 int tct_cnd_wait(tct_cnd_t *cond, tct_mtx_t *mtx); 317 318 /** Wait for a condition variable to become signaled. 319 * The function atomically unlocks the given mutex and endeavors to block until 320 * the given condition variable is signaled by a call to cnd_signal or to 321 * cnd_broadcast, or until after the specified time. When the calling thread 322 * becomes unblocked it locks the mutex before it returns. 323 * @param cond A condition variable object. 324 * @param mtx A mutex object. 325 * @param xt A point in time at which the request will time out (absolute time). 326 * @return @ref thrd_success upon success, or @ref thrd_timeout if the time 327 * specified in the call was reached without acquiring the requested resource, or 328 * @ref thrd_error if the request could not be honored. 329 */ 330 int tct_cnd_timedwait(tct_cnd_t *cond, tct_mtx_t *mtx, const struct timespec *ts); 331 332 /* Thread */ 333 #if defined(_TTHREAD_WIN32_) 334 typedef HANDLE tct_thrd_t; 335 #else 336 typedef pthread_t tct_thrd_t; 337 #endif 338 339 /** Thread start function. 340 * Any thread that is started with the @ref thrd_create() function must be 341 * started through a function of this type. 342 * @param arg The thread argument (the @c arg argument of the corresponding 343 * @ref thrd_create() call). 344 * @return The thread return value, which can be obtained by another thread 345 * by using the @ref thrd_join() function. 346 */ 347 typedef int (*tct_thrd_start_t)(void *arg); 348 349 /** Create a new thread. 350 * @param thr Identifier of the newly created thread. 351 * @param func A function pointer to the function that will be executed in 352 * the new thread. 353 * @param arg An argument to the thread function. 354 * @return @ref thrd_success on success, or @ref thrd_nomem if no memory could 355 * be allocated for the thread requested, or @ref thrd_error if the request 356 * could not be honored. 357 * @note A thread’s identifier may be reused for a different thread once the 358 * original thread has exited and either been detached or joined to another 359 * thread. 360 */ 361 int tct_thrd_create(tct_thrd_t *thr, tct_thrd_start_t func, void *arg); 362 363 /** Identify the calling thread. 364 * @return The identifier of the calling thread. 365 */ 366 tct_thrd_t tct_thrd_current(void); 367 368 /** Dispose of any resources allocated to the thread when that thread exits. 369 * @return thrd_success, or thrd_error on error 370 */ 371 int tct_thrd_detach(tct_thrd_t thr); 372 373 /** Compare two thread identifiers. 374 * The function determines if two thread identifiers refer to the same thread. 375 * @return Zero if the two thread identifiers refer to different threads. 376 * Otherwise a nonzero value is returned. 377 */ 378 int tct_thrd_equal(tct_thrd_t thr0, tct_thrd_t thr1); 379 380 /** Terminate execution of the calling thread. 381 * @param res Result code of the calling thread. 382 */ 383 TTHREAD_NORETURN void tct_thrd_exit(int res); 384 385 /** Wait for a thread to terminate. 386 * The function joins the given thread with the current thread by blocking 387 * until the other thread has terminated. 388 * @param thr The thread to join with. 389 * @param res If this pointer is not NULL, the function will store the result 390 * code of the given thread in the integer pointed to by @c res. 391 * @return @ref thrd_success on success, or @ref thrd_error if the request could 392 * not be honored. 393 */ 394 int tct_thrd_join(tct_thrd_t thr, int *res); 395 396 /** Put the calling thread to sleep. 397 * Suspend execution of the calling thread. 398 * @param duration Interval to sleep for 399 * @param remaining If non-NULL, this parameter will hold the remaining 400 * time until time_point upon return. This will 401 * typically be zero, but if the thread was woken up 402 * by a signal that is not ignored before duration was 403 * reached @c remaining will hold a positive time. 404 * @return 0 (zero) on successful sleep, -1 if an interrupt occurred, 405 * or a negative value if the operation fails. 406 */ 407 int tct_thrd_sleep(const struct timespec *duration, struct timespec *remaining); 408 409 /** Yield execution to another thread. 410 * Permit other threads to run, even if the current thread would ordinarily 411 * continue to run. 412 */ 413 void tct_thrd_yield(void); 414 415 /* Thread local storage */ 416 #if defined(_TTHREAD_WIN32_) 417 typedef DWORD tct_tss_t; 418 #else 419 typedef pthread_key_t tct_tss_t; 420 #endif 421 422 /** Destructor function for a thread-specific storage. 423 * @param val The value of the destructed thread-specific storage. 424 */ 425 typedef void (*tct_tss_dtor_t)(void *val); 426 427 /** Create a thread-specific storage. 428 * @param key The unique key identifier that will be set if the function is 429 * successful. 430 * @param dtor Destructor function. This can be NULL. 431 * @return @ref thrd_success on success, or @ref thrd_error if the request could 432 * not be honored. 433 * @note On Windows, the @c dtor will definitely be called when 434 * appropriate for threads created with @ref thrd_create. It will be 435 * called for other threads in most cases, the possible exception being 436 * for DLLs loaded with LoadLibraryEx. In order to be certain, you 437 * should use @ref thrd_create whenever possible. 438 */ 439 int tct_tss_create(tct_tss_t *key, tct_tss_dtor_t dtor); 440 441 /** Delete a thread-specific storage. 442 * The function releases any resources used by the given thread-specific 443 * storage. 444 * @param key The key that shall be deleted. 445 */ 446 void tct_tss_delete(tct_tss_t key); 447 448 /** Get the value for a thread-specific storage. 449 * @param key The thread-specific storage identifier. 450 * @return The value for the current thread held in the given thread-specific 451 * storage. 452 */ 453 void *tct_tss_get(tct_tss_t key); 454 455 /** Set the value for a thread-specific storage. 456 * @param key The thread-specific storage identifier. 457 * @param val The value of the thread-specific storage to set for the current 458 * thread. 459 * @return @ref thrd_success on success, or @ref thrd_error if the request could 460 * not be honored. 461 */ 462 int tct_tss_set(tct_tss_t key, void *val); 463 464 #if defined(_TTHREAD_WIN32_) 465 typedef struct { 466 LONG volatile status; 467 CRITICAL_SECTION lock; 468 } once_flag; 469 #define ONCE_FLAG_INIT {0,} 470 #else 471 #define once_flag pthread_once_t 472 #define ONCE_FLAG_INIT PTHREAD_ONCE_INIT 473 #endif 474 475 /** Invoke a callback exactly once 476 * @param flag Flag used to ensure the callback is invoked exactly 477 * once. 478 * @param func Callback to invoke. 479 */ 480 #if defined(_TTHREAD_WIN32_) 481 void tct_call_once(once_flag *flag, void (*func)(void)); 482 #else 483 #define tct_call_once(flag,func) pthread_once(flag,func) 484 #endif 485 486 #ifdef __cplusplus 487 } 488 #endif 489 490 #endif /* _TINYTHREAD_H_ */ 491