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