23 #define P99_THREADS_H 1
28 #if p99_has_feature(threads_h)
30 #elif defined(_XOPEN_SOURCE) || defined(_POSIX_C_SOURCE)
33 # error "no suitable thread implementation found"
36 #ifndef ONCE_FLAG_INIT
38 #define ONCE_FLAG_INIT P99_ONCE_FLAG_INIT
39 #define call_once p99_call_once
65 enum p00_once p00_done;
66 enum p00_once
volatile p00_vdone;
76 #define P99_DECLARE_INIT_ONCE(T, NAME, ARG) \
79 p99_once_flag p00_once; \
82 P99_DECLARE_STRUCT(NAME); \
84 void P99_PASTE3(p00_, NAME, _init_func)(T* ARG); \
86 void P99_PASTE3(p00_, NAME, _init_once)(NAME* ARG) { \
87 if (P99_UNLIKELY(!ARG->p00_once.p00_done.p00_done)) \
89 P99_SPIN_EXCLUDE(&ARG->p00_once.p00_flg) { \
90 if (!ARG->p00_once.p00_done.p00_vdone) { \
91 P99_PASTE3(p00_, NAME, _init_func)(&ARG->p00_val); \
92 ARG->p00_once.p00_done.p00_vdone = true; \
95 } while (!ARG->p00_once.p00_done.p00_vdone); \
98 void P99_PASTE3(p00_, NAME, _init_func)(T* ARG)
100 #define P99_INIT_ONCE(NAME, VARP) P99_PASTE3(p00_, NAME, _init_once)(VARP)
102 #define p00_call_once_2(FLAG, FUNC) \
104 p99_once_flag *p00Mflag = (FLAG); \
105 if (P99_UNLIKELY(p00Mflag->p00_done.p00_done != p00_once_finished)) \
107 atomic_flag_lock(&p00Mflag->p00_flg); \
108 switch (p00Mflag->p00_done.p00_vdone) { \
110 case p00_once_uninit: \
111 p00Mflag->p00_done.p00_done = 1; \
112 p00Mflag->p00_id = thrd_current(); \
113 atomic_flag_unlock(&p00Mflag->p00_flg); \
115 p00Mflag->p00_done.p00_done = 2; \
117 case p00_once_started: \
118 if (thrd_equal(p00Mflag->p00_id, thrd_current())) { \
120 atomic_flag_unlock(&p00Mflag->p00_flg); \
125 case p00_once_finished: \
126 atomic_flag_unlock(&p00Mflag->p00_flg); \
129 } while (p00Mflag && p00Mflag->p00_done.p00_vdone != p00_once_finished); \
134 p00_call_once_2(p00_flag, p00_flag->p00_init);
137 #define p00_call_once_3(FLAG, FUNC, ...) \
139 p99_once_flag *p00Mflag = (FLAG); \
140 if (P99_UNLIKELY(p00Mflag->p00_done.p00_done != p00_once_finished)) \
142 atomic_flag_lock(&p00Mflag->p00_flg); \
143 switch (p00Mflag->p00_done.p00_vdone) { \
145 case p00_once_uninit: \
146 p00Mflag->p00_done.p00_done = 1; \
147 p00Mflag->p00_id = thrd_current(); \
148 atomic_flag_unlock(&p00Mflag->p00_flg); \
150 p00Mflag->p00_done.p00_done = 2; \
152 case p00_once_started: \
153 if (thrd_equal(p00Mflag->p00_id, thrd_current())) { \
155 atomic_flag_unlock(&p00Mflag->p00_flg); \
160 case p00_once_finished: \
161 atomic_flag_unlock(&p00Mflag->p00_flg); \
164 } while (p00Mflag && p00Mflag->p00_done.p00_vdone != p00_once_finished); \
167 #define p00_call_once(N, ...) \
169 (p00_call_once_1(__VA_ARGS__)) \
171 (p00_call_once_2(__VA_ARGS__)) \
172 (p00_call_once_3(__VA_ARGS__)))
203 #define p99_call_once(FLAG, FUNC, ARG)
205 #define p99_call_once(...) p00_call_once(P99_NARG(__VA_ARGS__), __VA_ARGS__)
238 #define P99_DEFINE_ONCE_CHAIN(T, ...) \
239 p99_once_flag p99_ ## T ## _once; \
240 void p00_ ## T ## _once_init(void)
242 #define P99_DEFINE_ONCE_CHAIN(...) \
243 P99_IF_ELSE(P99_HAS_COMMA(__VA_ARGS__)) \
244 (P00_P99_DEFINE_ONCE_CHAIN_1(__VA_ARGS__)) \
245 (P00_P99_DEFINE_ONCE_CHAIN_0(__VA_ARGS__))
248 #define P00_P99_DEFINE_ONCE_CHAIN_0(T) \
249 static void P99_PASTE3(p00_, T, _once_init)(void); \
250 p99_once_flag P99_PASTE3(p99_, T, _once) = { \
251 .p00_init = P99_PASTE3(p00_, T, _once_init), \
253 static void P99_PASTE3(p00_, T, _once_init)(void)
255 #define P00_ONCE_INIT(_0, T, _2) P99_INIT_CHAIN(T)
257 #define P00_P99_DEFINE_ONCE_CHAIN_1(T, ...) \
258 static void P99_PASTE3(p00_, T, _once_init0)(void); \
259 static void P99_PASTE3(p00_, T, _once_init)(void) { \
260 P99_FOR(, P99_NARG(__VA_ARGS__), P00_SEP, P00_ONCE_INIT, __VA_ARGS__); \
262 P99_PASTE3(p00_, T, _once_init0)(); \
264 struct p99_once_flag P99_PASTE3(p99_, T, _once) = { \
265 .p00_init = P99_PASTE3(p00_, T, _once_init), \
267 static void P99_PASTE3(p00_, T, _once_init0)(void)
277 #define P99_DECLARE_ONCE_CHAIN(T) \
278 extern p99_once_flag P99_PASTE3(p99_, T, _once)
292 #define P99_INIT_CHAIN(T) \
293 p99_call_once(&P99_PASTE3(p99_, T, _once), P99_PASTE3(p99_, T, _once).p00_init)
309 #define P99_MUTUAL_EXCLUDE(MUT) P00_MUTUAL_EXCLUDE(MUT, P99_UNIQ(mut))
311 # if !P99_SIMPLE_BLOCKS
312 # define P00_MUTUAL_EXCLUDE(MUT, UNIQ) \
314 P00_BLK_DECL(int, p00_errNo, 0) \
315 P99_GUARDED_BLOCK(mtx_t*, \
318 (void)(P99_UNLIKELY(p00_errNo = mtx_lock(UNIQ)) \
319 && (fprintf(stderr, \
321 P99_STRINGIFY(__LINE__) ": lock error for " \
322 P99_STRINGIFY(MUT) ", %s\n", \
323 strerror(p00_errNo)), 1) \
325 && (P99_UNWIND(-1), 1) \
328 && mtx_unlock(UNIQ)))
330 # define P00_MUTUAL_EXCLUDE(MUT, UNIQ) \
332 P00_BLK_DECL(mtx_t*, UNIQ, &(MUT)) \
333 P00_BLK_BEFAFT(mtx_lock(UNIQ), mtx_unlock(UNIQ))
349 char const*
thrd2str(
char *p00_buf, thrd_t p00_id) {
350 unsigned char *p00_p = (
unsigned char*)&p00_id;
351 for (
size_t p00_i = 0; p00_i <
sizeof(thrd_t); ++p00_i) {
352 snprintf(p00_buf + 2*p00_i, 3,
"%02X", p00_p[p00_i]);
357 #define THRD2STR(ID) thrd2str((char[1 + sizeof(thrd_t) * 2]){0}, (ID))