mythread.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. /// \file mythread.h
  4. /// \brief Some threading related helper macros and functions
  5. //
  6. // Author: Lasse Collin
  7. //
  8. // This file has been put into the public domain.
  9. // You can do whatever you want with this file.
  10. //
  11. ///////////////////////////////////////////////////////////////////////////////
  12. #ifndef MYTHREAD_H
  13. #define MYTHREAD_H
  14. #include "sysdefs.h"
  15. // If any type of threading is enabled, #define MYTHREAD_ENABLED.
  16. #if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \
  17. || defined(MYTHREAD_VISTA)
  18. # define MYTHREAD_ENABLED 1
  19. #endif
  20. #ifdef MYTHREAD_ENABLED
  21. ////////////////////////////////////////
  22. // Shared between all threading types //
  23. ////////////////////////////////////////
  24. // Locks a mutex for a duration of a block.
  25. //
  26. // Perform mythread_mutex_lock(&mutex) in the beginning of a block
  27. // and mythread_mutex_unlock(&mutex) at the end of the block. "break"
  28. // may be used to unlock the mutex and jump out of the block.
  29. // mythread_sync blocks may be nested.
  30. //
  31. // Example:
  32. //
  33. // mythread_sync(mutex) {
  34. // foo();
  35. // if (some_error)
  36. // break; // Skips bar()
  37. // bar();
  38. // }
  39. //
  40. // At least GCC optimizes the loops completely away so it doesn't slow
  41. // things down at all compared to plain mythread_mutex_lock(&mutex)
  42. // and mythread_mutex_unlock(&mutex) calls.
  43. //
  44. #define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__)
  45. #define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line)
  46. #define mythread_sync_helper2(mutex, line) \
  47. for (unsigned int mythread_i_ ## line = 0; \
  48. mythread_i_ ## line \
  49. ? (mythread_mutex_unlock(&(mutex)), 0) \
  50. : (mythread_mutex_lock(&(mutex)), 1); \
  51. mythread_i_ ## line = 1) \
  52. for (unsigned int mythread_j_ ## line = 0; \
  53. !mythread_j_ ## line; \
  54. mythread_j_ ## line = 1)
  55. #endif
  56. #if !defined(MYTHREAD_ENABLED)
  57. //////////////////
  58. // No threading //
  59. //////////////////
  60. // Calls the given function once. This isn't thread safe.
  61. #define mythread_once(func) \
  62. do { \
  63. static bool once_ = false; \
  64. if (!once_) { \
  65. func(); \
  66. once_ = true; \
  67. } \
  68. } while (0)
  69. #if !(defined(_WIN32) && !defined(__CYGWIN__)) && !defined(__wasm__)
  70. // Use sigprocmask() to set the signal mask in single-threaded programs.
  71. #include <signal.h>
  72. static inline void
  73. mythread_sigmask(int how, const sigset_t *restrict set,
  74. sigset_t *restrict oset)
  75. {
  76. int ret = sigprocmask(how, set, oset);
  77. assert(ret == 0);
  78. (void)ret;
  79. }
  80. #endif
  81. #elif defined(MYTHREAD_POSIX)
  82. ////////////////////
  83. // Using pthreads //
  84. ////////////////////
  85. #include <pthread.h>
  86. #include <signal.h>
  87. #include <time.h>
  88. #include <errno.h>
  89. // If clock_gettime() isn't available, use gettimeofday() from <sys/time.h>
  90. // as a fallback. gettimeofday() is in SUSv2 and thus is supported on all
  91. // relevant POSIX systems.
  92. #ifndef HAVE_CLOCK_GETTIME
  93. # include <sys/time.h>
  94. #endif
  95. #define MYTHREAD_RET_TYPE void *
  96. #define MYTHREAD_RET_VALUE NULL
  97. typedef pthread_t mythread;
  98. typedef pthread_mutex_t mythread_mutex;
  99. typedef struct {
  100. pthread_cond_t cond;
  101. #ifdef HAVE_CLOCK_GETTIME
  102. // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
  103. // the condition variable.
  104. clockid_t clk_id;
  105. #endif
  106. } mythread_cond;
  107. typedef struct timespec mythread_condtime;
  108. // Calls the given function once in a thread-safe way.
  109. #define mythread_once(func) \
  110. do { \
  111. static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
  112. pthread_once(&once_, &func); \
  113. } while (0)
  114. // Use pthread_sigmask() to set the signal mask in multi-threaded programs.
  115. // Do nothing on OpenVMS since it lacks pthread_sigmask().
  116. static inline void
  117. mythread_sigmask(int how, const sigset_t *restrict set,
  118. sigset_t *restrict oset)
  119. {
  120. #ifdef __VMS
  121. (void)how;
  122. (void)set;
  123. (void)oset;
  124. #else
  125. int ret = pthread_sigmask(how, set, oset);
  126. assert(ret == 0);
  127. (void)ret;
  128. #endif
  129. }
  130. // Creates a new thread with all signals blocked. Returns zero on success
  131. // and non-zero on error.
  132. static inline int
  133. mythread_create(mythread *thread, void *(*func)(void *arg), void *arg)
  134. {
  135. sigset_t old;
  136. sigset_t all;
  137. sigfillset(&all);
  138. mythread_sigmask(SIG_SETMASK, &all, &old);
  139. const int ret = pthread_create(thread, NULL, func, arg);
  140. mythread_sigmask(SIG_SETMASK, &old, NULL);
  141. return ret;
  142. }
  143. // Joins a thread. Returns zero on success and non-zero on error.
  144. static inline int
  145. mythread_join(mythread thread)
  146. {
  147. return pthread_join(thread, NULL);
  148. }
  149. // Initiatlizes a mutex. Returns zero on success and non-zero on error.
  150. static inline int
  151. mythread_mutex_init(mythread_mutex *mutex)
  152. {
  153. return pthread_mutex_init(mutex, NULL);
  154. }
  155. static inline void
  156. mythread_mutex_destroy(mythread_mutex *mutex)
  157. {
  158. int ret = pthread_mutex_destroy(mutex);
  159. assert(ret == 0);
  160. (void)ret;
  161. }
  162. static inline void
  163. mythread_mutex_lock(mythread_mutex *mutex)
  164. {
  165. int ret = pthread_mutex_lock(mutex);
  166. assert(ret == 0);
  167. (void)ret;
  168. }
  169. static inline void
  170. mythread_mutex_unlock(mythread_mutex *mutex)
  171. {
  172. int ret = pthread_mutex_unlock(mutex);
  173. assert(ret == 0);
  174. (void)ret;
  175. }
  176. // Initializes a condition variable.
  177. //
  178. // Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the
  179. // timeout in pthread_cond_timedwait() work correctly also if system time
  180. // is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available
  181. // everywhere while the default CLOCK_REALTIME is, so the default is
  182. // used if CLOCK_MONOTONIC isn't available.
  183. //
  184. // If clock_gettime() isn't available at all, gettimeofday() will be used.
  185. static inline int
  186. mythread_cond_init(mythread_cond *mycond)
  187. {
  188. #ifdef HAVE_CLOCK_GETTIME
  189. # if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \
  190. defined(HAVE_CLOCK_MONOTONIC)
  191. struct timespec ts;
  192. pthread_condattr_t condattr;
  193. // POSIX doesn't seem to *require* that pthread_condattr_setclock()
  194. // will fail if given an unsupported clock ID. Test that
  195. // CLOCK_MONOTONIC really is supported using clock_gettime().
  196. if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0
  197. && pthread_condattr_init(&condattr) == 0) {
  198. int ret = pthread_condattr_setclock(
  199. &condattr, CLOCK_MONOTONIC);
  200. if (ret == 0)
  201. ret = pthread_cond_init(&mycond->cond, &condattr);
  202. pthread_condattr_destroy(&condattr);
  203. if (ret == 0) {
  204. mycond->clk_id = CLOCK_MONOTONIC;
  205. return 0;
  206. }
  207. }
  208. // If anything above fails, fall back to the default CLOCK_REALTIME.
  209. // POSIX requires that all implementations of clock_gettime() must
  210. // support at least CLOCK_REALTIME.
  211. # endif
  212. mycond->clk_id = CLOCK_REALTIME;
  213. #endif
  214. return pthread_cond_init(&mycond->cond, NULL);
  215. }
  216. static inline void
  217. mythread_cond_destroy(mythread_cond *cond)
  218. {
  219. int ret = pthread_cond_destroy(&cond->cond);
  220. assert(ret == 0);
  221. (void)ret;
  222. }
  223. static inline void
  224. mythread_cond_signal(mythread_cond *cond)
  225. {
  226. int ret = pthread_cond_signal(&cond->cond);
  227. assert(ret == 0);
  228. (void)ret;
  229. }
  230. static inline void
  231. mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
  232. {
  233. int ret = pthread_cond_wait(&cond->cond, mutex);
  234. assert(ret == 0);
  235. (void)ret;
  236. }
  237. // Waits on a condition or until a timeout expires. If the timeout expires,
  238. // non-zero is returned, otherwise zero is returned.
  239. static inline int
  240. mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
  241. const mythread_condtime *condtime)
  242. {
  243. int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime);
  244. assert(ret == 0 || ret == ETIMEDOUT);
  245. return ret;
  246. }
  247. // Sets condtime to the absolute time that is timeout_ms milliseconds
  248. // in the future. The type of the clock to use is taken from cond.
  249. static inline void
  250. mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
  251. uint32_t timeout_ms)
  252. {
  253. condtime->tv_sec = (time_t)(timeout_ms / 1000);
  254. condtime->tv_nsec = (long)((timeout_ms % 1000) * 1000000);
  255. #ifdef HAVE_CLOCK_GETTIME
  256. struct timespec now;
  257. int ret = clock_gettime(cond->clk_id, &now);
  258. assert(ret == 0);
  259. (void)ret;
  260. condtime->tv_sec += now.tv_sec;
  261. condtime->tv_nsec += now.tv_nsec;
  262. #else
  263. (void)cond;
  264. struct timeval now;
  265. gettimeofday(&now, NULL);
  266. condtime->tv_sec += now.tv_sec;
  267. condtime->tv_nsec += now.tv_usec * 1000L;
  268. #endif
  269. // tv_nsec must stay in the range [0, 999_999_999].
  270. if (condtime->tv_nsec >= 1000000000L) {
  271. condtime->tv_nsec -= 1000000000L;
  272. ++condtime->tv_sec;
  273. }
  274. }
  275. #elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
  276. /////////////////////
  277. // Windows threads //
  278. /////////////////////
  279. #define WIN32_LEAN_AND_MEAN
  280. #ifdef MYTHREAD_VISTA
  281. # undef _WIN32_WINNT
  282. # define _WIN32_WINNT 0x0600
  283. #endif
  284. #include <windows.h>
  285. #include <process.h>
  286. #define MYTHREAD_RET_TYPE unsigned int __stdcall
  287. #define MYTHREAD_RET_VALUE 0
  288. typedef HANDLE mythread;
  289. typedef CRITICAL_SECTION mythread_mutex;
  290. #ifdef MYTHREAD_WIN95
  291. typedef HANDLE mythread_cond;
  292. #else
  293. typedef CONDITION_VARIABLE mythread_cond;
  294. #endif
  295. typedef struct {
  296. // Tick count (milliseconds) in the beginning of the timeout.
  297. // NOTE: This is 32 bits so it wraps around after 49.7 days.
  298. // Multi-day timeouts may not work as expected.
  299. DWORD start;
  300. // Length of the timeout in milliseconds. The timeout expires
  301. // when the current tick count minus "start" is equal or greater
  302. // than "timeout".
  303. DWORD timeout;
  304. } mythread_condtime;
  305. // mythread_once() is only available with Vista threads.
  306. #ifdef MYTHREAD_VISTA
  307. #define mythread_once(func) \
  308. do { \
  309. static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
  310. BOOL pending_; \
  311. if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
  312. abort(); \
  313. if (pending_) { \
  314. func(); \
  315. if (!InitOnceComplete(&once_, 0, NULL)) \
  316. abort(); \
  317. } \
  318. } while (0)
  319. #endif
  320. // mythread_sigmask() isn't available on Windows. Even a dummy version would
  321. // make no sense because the other POSIX signal functions are missing anyway.
  322. static inline int
  323. mythread_create(mythread *thread,
  324. unsigned int (__stdcall *func)(void *arg), void *arg)
  325. {
  326. uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
  327. if (ret == 0)
  328. return -1;
  329. *thread = (HANDLE)ret;
  330. return 0;
  331. }
  332. static inline int
  333. mythread_join(mythread thread)
  334. {
  335. int ret = 0;
  336. if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
  337. ret = -1;
  338. if (!CloseHandle(thread))
  339. ret = -1;
  340. return ret;
  341. }
  342. static inline int
  343. mythread_mutex_init(mythread_mutex *mutex)
  344. {
  345. InitializeCriticalSection(mutex);
  346. return 0;
  347. }
  348. static inline void
  349. mythread_mutex_destroy(mythread_mutex *mutex)
  350. {
  351. DeleteCriticalSection(mutex);
  352. }
  353. static inline void
  354. mythread_mutex_lock(mythread_mutex *mutex)
  355. {
  356. EnterCriticalSection(mutex);
  357. }
  358. static inline void
  359. mythread_mutex_unlock(mythread_mutex *mutex)
  360. {
  361. LeaveCriticalSection(mutex);
  362. }
  363. static inline int
  364. mythread_cond_init(mythread_cond *cond)
  365. {
  366. #ifdef MYTHREAD_WIN95
  367. *cond = CreateEvent(NULL, FALSE, FALSE, NULL);
  368. return *cond == NULL ? -1 : 0;
  369. #else
  370. InitializeConditionVariable(cond);
  371. return 0;
  372. #endif
  373. }
  374. static inline void
  375. mythread_cond_destroy(mythread_cond *cond)
  376. {
  377. #ifdef MYTHREAD_WIN95
  378. CloseHandle(*cond);
  379. #else
  380. (void)cond;
  381. #endif
  382. }
  383. static inline void
  384. mythread_cond_signal(mythread_cond *cond)
  385. {
  386. #ifdef MYTHREAD_WIN95
  387. SetEvent(*cond);
  388. #else
  389. WakeConditionVariable(cond);
  390. #endif
  391. }
  392. static inline void
  393. mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
  394. {
  395. #ifdef MYTHREAD_WIN95
  396. LeaveCriticalSection(mutex);
  397. WaitForSingleObject(*cond, INFINITE);
  398. EnterCriticalSection(mutex);
  399. #else
  400. BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
  401. assert(ret);
  402. (void)ret;
  403. #endif
  404. }
  405. static inline int
  406. mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
  407. const mythread_condtime *condtime)
  408. {
  409. #ifdef MYTHREAD_WIN95
  410. LeaveCriticalSection(mutex);
  411. #endif
  412. DWORD elapsed = GetTickCount() - condtime->start;
  413. DWORD timeout = elapsed >= condtime->timeout
  414. ? 0 : condtime->timeout - elapsed;
  415. #ifdef MYTHREAD_WIN95
  416. DWORD ret = WaitForSingleObject(*cond, timeout);
  417. assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
  418. EnterCriticalSection(mutex);
  419. return ret == WAIT_TIMEOUT;
  420. #else
  421. BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
  422. assert(ret || GetLastError() == ERROR_TIMEOUT);
  423. return !ret;
  424. #endif
  425. }
  426. static inline void
  427. mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
  428. uint32_t timeout)
  429. {
  430. (void)cond;
  431. condtime->start = GetTickCount();
  432. condtime->timeout = timeout;
  433. }
  434. #endif
  435. #endif