1 /*
2  * C11 <threads.h> emulation library
3  *
4  * (C) Copyright yohhoy 2012.
5  * Distributed under the Boost Software License, Version 1.0.
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare [[derivative work]]s of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  */
29 #ifndef EMULATED_THREADS_H_INCLUDED_
30 #define EMULATED_THREADS_H_INCLUDED_
31 
32 #include <time.h>
33 
34 #ifndef TIME_UTC
35 #define TIME_UTC 1
36 #endif
37 
38 #if defined(_WIN32)
39 #include <windows.h>
40 
41 // check configuration
42 #if defined(EMULATED_THREADS_USE_NATIVE_CALL_ONCE) && (_WIN32_WINNT < 0x0600)
43 #error EMULATED_THREADS_USE_NATIVE_CALL_ONCE requires _WIN32_WINNT>=0x0600
44 #endif
45 
46 #if defined(EMULATED_THREADS_USE_NATIVE_CV) && (_WIN32_WINNT < 0x0600)
47 #error EMULATED_THREADS_USE_NATIVE_CV requires _WIN32_WINNT>=0x0600
48 #endif
49 
50 
51 /*---------------------------- macros ----------------------------*/
52 #ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
53 #define ONCE_FLAG_INIT INIT_ONCE_STATIC_INIT
54 #else
55 #define ONCE_FLAG_INIT {0}
56 #endif
57 #define TSS_DTOR_ITERATIONS 1
58 
59 /*---------------------------- types ----------------------------*/
60 typedef struct cnd_t {
61 #ifdef EMULATED_THREADS_USE_NATIVE_CV
62     CONDITION_VARIABLE condvar;
63 #else
64     int blocked;
65     int gone;
66     int to_unblock;
67     HANDLE sem_queue;
68     HANDLE sem_gate;
69     CRITICAL_SECTION monitor;
70 #endif
71 } cnd_t;
72 
73 typedef HANDLE thrd_t;
74 
75 typedef DWORD tss_t;
76 
77 typedef struct mtx_t {
78     CRITICAL_SECTION cs;
79 } mtx_t;
80 
81 #ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
82 typedef INIT_ONCE once_flag;
83 #else
84 typedef struct once_flag_t {
85     volatile LONG status;
86 } once_flag;
87 #endif
88 
89 #elif defined(__unix__) || defined(__unix) || defined(__APPLE__)
90 #include <pthread.h>
91 
92 /*---------------------------- macros ----------------------------*/
93 #define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
94 #ifdef INIT_ONCE_STATIC_INIT
95 #define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
96 #else
97 #define TSS_DTOR_ITERATIONS 1  // assume TSS dtor MAY be called at least once.
98 #endif
99 
100 /*---------------------------- types ----------------------------*/
101 typedef pthread_cond_t  cnd_t;
102 typedef pthread_t       thrd_t;
103 typedef pthread_key_t   tss_t;
104 typedef pthread_mutex_t mtx_t;
105 typedef pthread_once_t  once_flag;
106 
107 #else
108 #error Not supported on this platform.
109 #endif
110 
111 
112 /*---------------------------- types ----------------------------*/
113 typedef void (*tss_dtor_t)(void*);
114 typedef int (*thrd_start_t)(void*);
115 
116 struct xtime {
117     time_t sec;
118     long nsec;
119 };
120 typedef struct xtime xtime;
121 
122 
123 /*-------------------- enumeration constants --------------------*/
124 enum {
125     mtx_plain     = 0,
126     mtx_try       = 1,
127     mtx_timed     = 2,
128     mtx_recursive = 4
129 };
130 
131 enum {
132     thrd_success = 0, // succeeded
133     thrd_timeout,     // timeout
134     thrd_error,       // failed
135     thrd_busy,        // resource busy
136     thrd_nomem        // out of memory
137 };
138 
139 
140 /*-------------------------- functions --------------------------*/
141 void call_once(once_flag *flag, void (*func)(void));
142 
143 int cnd_broadcast(cnd_t *cond);
144 void cnd_destroy(cnd_t *cond);
145 int cnd_init(cnd_t *cond);
146 int cnd_signal(cnd_t *cond);
147 int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt);
148 int cnd_wait(cnd_t *cond, mtx_t *mtx);
149 
150 void mtx_destroy(mtx_t *mtx);
151 int mtx_init(mtx_t *mtx, int type);
152 int mtx_lock(mtx_t *mtx);
153 int mtx_timedlock(mtx_t *mtx, const xtime *xt);
154 int mtx_trylock(mtx_t *mtx);
155 int mtx_unlock(mtx_t *mtx);
156 
157 int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
158 thrd_t thrd_current(void);
159 int thrd_detach(thrd_t thr);
160 int thrd_equal(thrd_t thr0, thrd_t thr1);
161 void thrd_exit(int res);
162 int thrd_join(thrd_t thr, int *res);
163 void thrd_sleep(const xtime *xt);
164 void thrd_yield(void);
165 
166 int tss_create(tss_t *key, tss_dtor_t dtor);
167 void tss_delete(tss_t key);
168 void *tss_get(tss_t key);
169 int tss_set(tss_t key, void *val);
170 
171 int xtime_get(xtime *xt, int base);
172 
173 
174 #endif /* EMULATED_THREADS_H_INCLUDED_ */
175