tinycthread.h 16 KB

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