mythread.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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__))
  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 <sys/time.h>
  86. #include <pthread.h>
  87. #include <signal.h>
  88. #include <time.h>
  89. #include <errno.h>
  90. #define MYTHREAD_RET_TYPE void *
  91. #define MYTHREAD_RET_VALUE NULL
  92. typedef pthread_t mythread;
  93. typedef pthread_mutex_t mythread_mutex;
  94. typedef struct {
  95. pthread_cond_t cond;
  96. #ifdef HAVE_CLOCK_GETTIME
  97. // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
  98. // the condition variable.
  99. clockid_t clk_id;
  100. #endif
  101. } mythread_cond;
  102. typedef struct timespec mythread_condtime;
  103. // Calls the given function once in a thread-safe way.
  104. #define mythread_once(func) \
  105. do { \
  106. static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
  107. pthread_once(&once_, &func); \
  108. } while (0)
  109. // Use pthread_sigmask() to set the signal mask in multi-threaded programs.
  110. // Do nothing on OpenVMS since it lacks pthread_sigmask().
  111. static inline void
  112. mythread_sigmask(int how, const sigset_t *restrict set,
  113. sigset_t *restrict oset)
  114. {
  115. #ifdef __VMS
  116. (void)how;
  117. (void)set;
  118. (void)oset;
  119. #else
  120. int ret = pthread_sigmask(how, set, oset);
  121. assert(ret == 0);
  122. (void)ret;
  123. #endif
  124. }
  125. // Creates a new thread with all signals blocked. Returns zero on success
  126. // and non-zero on error.
  127. static inline int
  128. mythread_create(mythread *thread, void *(*func)(void *arg), void *arg)
  129. {
  130. sigset_t old;
  131. sigset_t all;
  132. sigfillset(&all);
  133. mythread_sigmask(SIG_SETMASK, &all, &old);
  134. const int ret = pthread_create(thread, NULL, func, arg);
  135. mythread_sigmask(SIG_SETMASK, &old, NULL);
  136. return ret;
  137. }
  138. // Joins a thread. Returns zero on success and non-zero on error.
  139. static inline int
  140. mythread_join(mythread thread)
  141. {
  142. return pthread_join(thread, NULL);
  143. }
  144. // Initiatlizes a mutex. Returns zero on success and non-zero on error.
  145. static inline int
  146. mythread_mutex_init(mythread_mutex *mutex)
  147. {
  148. return pthread_mutex_init(mutex, NULL);
  149. }
  150. static inline void
  151. mythread_mutex_destroy(mythread_mutex *mutex)
  152. {
  153. int ret = pthread_mutex_destroy(mutex);
  154. assert(ret == 0);
  155. (void)ret;
  156. }
  157. static inline void
  158. mythread_mutex_lock(mythread_mutex *mutex)
  159. {
  160. int ret = pthread_mutex_lock(mutex);
  161. assert(ret == 0);
  162. (void)ret;
  163. }
  164. static inline void
  165. mythread_mutex_unlock(mythread_mutex *mutex)
  166. {
  167. int ret = pthread_mutex_unlock(mutex);
  168. assert(ret == 0);
  169. (void)ret;
  170. }
  171. // Initializes a condition variable.
  172. //
  173. // Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the
  174. // timeout in pthread_cond_timedwait() work correctly also if system time
  175. // is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available
  176. // everywhere while the default CLOCK_REALTIME is, so the default is
  177. // used if CLOCK_MONOTONIC isn't available.
  178. //
  179. // If clock_gettime() isn't available at all, gettimeofday() will be used.
  180. static inline int
  181. mythread_cond_init(mythread_cond *mycond)
  182. {
  183. #ifdef HAVE_CLOCK_GETTIME
  184. // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1.
  185. # if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && HAVE_DECL_CLOCK_MONOTONIC
  186. struct timespec ts;
  187. pthread_condattr_t condattr;
  188. // POSIX doesn't seem to *require* that pthread_condattr_setclock()
  189. // will fail if given an unsupported clock ID. Test that
  190. // CLOCK_MONOTONIC really is supported using clock_gettime().
  191. if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0
  192. && pthread_condattr_init(&condattr) == 0) {
  193. int ret = pthread_condattr_setclock(
  194. &condattr, CLOCK_MONOTONIC);
  195. if (ret == 0)
  196. ret = pthread_cond_init(&mycond->cond, &condattr);
  197. pthread_condattr_destroy(&condattr);
  198. if (ret == 0) {
  199. mycond->clk_id = CLOCK_MONOTONIC;
  200. return 0;
  201. }
  202. }
  203. // If anything above fails, fall back to the default CLOCK_REALTIME.
  204. // POSIX requires that all implementations of clock_gettime() must
  205. // support at least CLOCK_REALTIME.
  206. # endif
  207. mycond->clk_id = CLOCK_REALTIME;
  208. #endif
  209. return pthread_cond_init(&mycond->cond, NULL);
  210. }
  211. static inline void
  212. mythread_cond_destroy(mythread_cond *cond)
  213. {
  214. int ret = pthread_cond_destroy(&cond->cond);
  215. assert(ret == 0);
  216. (void)ret;
  217. }
  218. static inline void
  219. mythread_cond_signal(mythread_cond *cond)
  220. {
  221. int ret = pthread_cond_signal(&cond->cond);
  222. assert(ret == 0);
  223. (void)ret;
  224. }
  225. static inline void
  226. mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
  227. {
  228. int ret = pthread_cond_wait(&cond->cond, mutex);
  229. assert(ret == 0);
  230. (void)ret;
  231. }
  232. // Waits on a condition or until a timeout expires. If the timeout expires,
  233. // non-zero is returned, otherwise zero is returned.
  234. static inline int
  235. mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
  236. const mythread_condtime *condtime)
  237. {
  238. int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime);
  239. assert(ret == 0 || ret == ETIMEDOUT);
  240. return ret;
  241. }
  242. // Sets condtime to the absolute time that is timeout_ms milliseconds
  243. // in the future. The type of the clock to use is taken from cond.
  244. static inline void
  245. mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
  246. uint32_t timeout_ms)
  247. {
  248. condtime->tv_sec = timeout_ms / 1000;
  249. condtime->tv_nsec = (timeout_ms % 1000) * 1000000;
  250. #ifdef HAVE_CLOCK_GETTIME
  251. struct timespec now;
  252. int ret = clock_gettime(cond->clk_id, &now);
  253. assert(ret == 0);
  254. (void)ret;
  255. condtime->tv_sec += now.tv_sec;
  256. condtime->tv_nsec += now.tv_nsec;
  257. #else
  258. (void)cond;
  259. struct timeval now;
  260. gettimeofday(&now, NULL);
  261. condtime->tv_sec += now.tv_sec;
  262. condtime->tv_nsec += now.tv_usec * 1000L;
  263. #endif
  264. // tv_nsec must stay in the range [0, 999_999_999].
  265. if (condtime->tv_nsec >= 1000000000L) {
  266. condtime->tv_nsec -= 1000000000L;
  267. ++condtime->tv_sec;
  268. }
  269. }
  270. #elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
  271. /////////////////////
  272. // Windows threads //
  273. /////////////////////
  274. #define WIN32_LEAN_AND_MEAN
  275. #ifdef MYTHREAD_VISTA
  276. # undef _WIN32_WINNT
  277. # define _WIN32_WINNT 0x0600
  278. #endif
  279. #include <windows.h>
  280. #include <process.h>
  281. #define MYTHREAD_RET_TYPE unsigned int __stdcall
  282. #define MYTHREAD_RET_VALUE 0
  283. typedef HANDLE mythread;
  284. typedef CRITICAL_SECTION mythread_mutex;
  285. #ifdef MYTHREAD_WIN95
  286. typedef HANDLE mythread_cond;
  287. #else
  288. typedef CONDITION_VARIABLE mythread_cond;
  289. #endif
  290. typedef struct {
  291. // Tick count (milliseconds) in the beginning of the timeout.
  292. // NOTE: This is 32 bits so it wraps around after 49.7 days.
  293. // Multi-day timeouts may not work as expected.
  294. DWORD start;
  295. // Length of the timeout in milliseconds. The timeout expires
  296. // when the current tick count minus "start" is equal or greater
  297. // than "timeout".
  298. DWORD timeout;
  299. } mythread_condtime;
  300. // mythread_once() is only available with Vista threads.
  301. #ifdef MYTHREAD_VISTA
  302. #define mythread_once(func) \
  303. do { \
  304. static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
  305. BOOL pending_; \
  306. if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
  307. abort(); \
  308. if (pending_) { \
  309. func(); \
  310. if (!InitOnceComplete(&once, 0, NULL)) \
  311. abort(); \
  312. } \
  313. } while (0)
  314. #endif
  315. // mythread_sigmask() isn't available on Windows. Even a dummy version would
  316. // make no sense because the other POSIX signal functions are missing anyway.
  317. static inline int
  318. mythread_create(mythread *thread,
  319. unsigned int (__stdcall *func)(void *arg), void *arg)
  320. {
  321. uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
  322. if (ret == 0)
  323. return -1;
  324. *thread = (HANDLE)ret;
  325. return 0;
  326. }
  327. static inline int
  328. mythread_join(mythread thread)
  329. {
  330. int ret = 0;
  331. if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
  332. ret = -1;
  333. if (!CloseHandle(thread))
  334. ret = -1;
  335. return ret;
  336. }
  337. static inline int
  338. mythread_mutex_init(mythread_mutex *mutex)
  339. {
  340. InitializeCriticalSection(mutex);
  341. return 0;
  342. }
  343. static inline void
  344. mythread_mutex_destroy(mythread_mutex *mutex)
  345. {
  346. DeleteCriticalSection(mutex);
  347. }
  348. static inline void
  349. mythread_mutex_lock(mythread_mutex *mutex)
  350. {
  351. EnterCriticalSection(mutex);
  352. }
  353. static inline void
  354. mythread_mutex_unlock(mythread_mutex *mutex)
  355. {
  356. LeaveCriticalSection(mutex);
  357. }
  358. static inline int
  359. mythread_cond_init(mythread_cond *cond)
  360. {
  361. #ifdef MYTHREAD_WIN95
  362. *cond = CreateEvent(NULL, FALSE, FALSE, NULL);
  363. return *cond == NULL ? -1 : 0;
  364. #else
  365. InitializeConditionVariable(cond);
  366. return 0;
  367. #endif
  368. }
  369. static inline void
  370. mythread_cond_destroy(mythread_cond *cond)
  371. {
  372. #ifdef MYTHREAD_WIN95
  373. CloseHandle(*cond);
  374. #else
  375. (void)cond;
  376. #endif
  377. }
  378. static inline void
  379. mythread_cond_signal(mythread_cond *cond)
  380. {
  381. #ifdef MYTHREAD_WIN95
  382. SetEvent(*cond);
  383. #else
  384. WakeConditionVariable(cond);
  385. #endif
  386. }
  387. static inline void
  388. mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
  389. {
  390. #ifdef MYTHREAD_WIN95
  391. LeaveCriticalSection(mutex);
  392. WaitForSingleObject(*cond, INFINITE);
  393. EnterCriticalSection(mutex);
  394. #else
  395. BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
  396. assert(ret);
  397. (void)ret;
  398. #endif
  399. }
  400. static inline int
  401. mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
  402. const mythread_condtime *condtime)
  403. {
  404. #ifdef MYTHREAD_WIN95
  405. LeaveCriticalSection(mutex);
  406. #endif
  407. DWORD elapsed = GetTickCount() - condtime->start;
  408. DWORD timeout = elapsed >= condtime->timeout
  409. ? 0 : condtime->timeout - elapsed;
  410. #ifdef MYTHREAD_WIN95
  411. DWORD ret = WaitForSingleObject(*cond, timeout);
  412. assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
  413. EnterCriticalSection(mutex);
  414. return ret == WAIT_TIMEOUT;
  415. #else
  416. BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
  417. assert(ret || GetLastError() == ERROR_TIMEOUT);
  418. return !ret;
  419. #endif
  420. }
  421. static inline void
  422. mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
  423. uint32_t timeout)
  424. {
  425. (void)cond;
  426. condtime->start = GetTickCount();
  427. condtime->timeout = timeout;
  428. }
  429. #endif
  430. #endif