1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * C11 <threads.h> emulation library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * (C) Copyright yohhoy 2012.
5bf215546Sopenharmony_ci * Distributed under the Boost Software License, Version 1.0.
6bf215546Sopenharmony_ci *
7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person or organization
8bf215546Sopenharmony_ci * obtaining a copy of the software and accompanying documentation covered by
9bf215546Sopenharmony_ci * this license (the "Software") to use, reproduce, display, distribute,
10bf215546Sopenharmony_ci * execute, and transmit the Software, and to prepare [[derivative work]]s of the
11bf215546Sopenharmony_ci * Software, and to permit third-parties to whom the Software is furnished to
12bf215546Sopenharmony_ci * do so, all subject to the following:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The copyright notices in the Software and this entire statement, including
15bf215546Sopenharmony_ci * the above license grant, this restriction and the following disclaimer,
16bf215546Sopenharmony_ci * must be included in all copies of the Software, in whole or in part, and
17bf215546Sopenharmony_ci * all derivative works of the Software, unless such copies or derivative
18bf215546Sopenharmony_ci * works are solely in the form of machine-executable object code generated by
19bf215546Sopenharmony_ci * a source language processor.
20bf215546Sopenharmony_ci *
21bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24bf215546Sopenharmony_ci * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25bf215546Sopenharmony_ci * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
28bf215546Sopenharmony_ci */
29bf215546Sopenharmony_ci#include <stdlib.h>
30bf215546Sopenharmony_ci#include <assert.h>
31bf215546Sopenharmony_ci#include <limits.h>
32bf215546Sopenharmony_ci#include <errno.h>
33bf215546Sopenharmony_ci#include <unistd.h>
34bf215546Sopenharmony_ci#include <sched.h>
35bf215546Sopenharmony_ci#include <stdint.h> /* for intptr_t */
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#include "c11/threads.h"
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci/*
40bf215546Sopenharmony_ciConfiguration macro:
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci  EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
43bf215546Sopenharmony_ci    Use pthread_mutex_timedlock() for `mtx_timedlock()'
44bf215546Sopenharmony_ci    Otherwise use mtx_trylock() + *busy loop* emulation.
45bf215546Sopenharmony_ci*/
46bf215546Sopenharmony_ci#if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__NetBSD__)
47bf215546Sopenharmony_ci#define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
48bf215546Sopenharmony_ci#endif
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci/*---------------------------- types ----------------------------*/
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci/*
53bf215546Sopenharmony_ciImplementation limits:
54bf215546Sopenharmony_ci  - Conditionally emulation for "mutex with timeout"
55bf215546Sopenharmony_ci    (see EMULATED_THREADS_USE_NATIVE_TIMEDLOCK macro)
56bf215546Sopenharmony_ci*/
57bf215546Sopenharmony_cistruct impl_thrd_param {
58bf215546Sopenharmony_ci    thrd_start_t func;
59bf215546Sopenharmony_ci    void *arg;
60bf215546Sopenharmony_ci};
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_cistatic void *
63bf215546Sopenharmony_ciimpl_thrd_routine(void *p)
64bf215546Sopenharmony_ci{
65bf215546Sopenharmony_ci    struct impl_thrd_param pack = *((struct impl_thrd_param *)p);
66bf215546Sopenharmony_ci    free(p);
67bf215546Sopenharmony_ci    return (void*)(intptr_t)pack.func(pack.arg);
68bf215546Sopenharmony_ci}
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci/*--------------- 7.25.2 Initialization functions ---------------*/
72bf215546Sopenharmony_ci// 7.25.2.1
73bf215546Sopenharmony_civoid
74bf215546Sopenharmony_cicall_once(once_flag *flag, void (*func)(void))
75bf215546Sopenharmony_ci{
76bf215546Sopenharmony_ci    pthread_once(flag, func);
77bf215546Sopenharmony_ci}
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci/*------------- 7.25.3 Condition variable functions -------------*/
81bf215546Sopenharmony_ci// 7.25.3.1
82bf215546Sopenharmony_ciint
83bf215546Sopenharmony_cicnd_broadcast(cnd_t *cond)
84bf215546Sopenharmony_ci{
85bf215546Sopenharmony_ci    assert(cond != NULL);
86bf215546Sopenharmony_ci    return (pthread_cond_broadcast(cond) == 0) ? thrd_success : thrd_error;
87bf215546Sopenharmony_ci}
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci// 7.25.3.2
90bf215546Sopenharmony_civoid
91bf215546Sopenharmony_cicnd_destroy(cnd_t *cond)
92bf215546Sopenharmony_ci{
93bf215546Sopenharmony_ci    assert(cond);
94bf215546Sopenharmony_ci    pthread_cond_destroy(cond);
95bf215546Sopenharmony_ci}
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci// 7.25.3.3
98bf215546Sopenharmony_ciint
99bf215546Sopenharmony_cicnd_init(cnd_t *cond)
100bf215546Sopenharmony_ci{
101bf215546Sopenharmony_ci    assert(cond != NULL);
102bf215546Sopenharmony_ci    return (pthread_cond_init(cond, NULL) == 0) ? thrd_success : thrd_error;
103bf215546Sopenharmony_ci}
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci// 7.25.3.4
106bf215546Sopenharmony_ciint
107bf215546Sopenharmony_cicnd_signal(cnd_t *cond)
108bf215546Sopenharmony_ci{
109bf215546Sopenharmony_ci    assert(cond != NULL);
110bf215546Sopenharmony_ci    return (pthread_cond_signal(cond) == 0) ? thrd_success : thrd_error;
111bf215546Sopenharmony_ci}
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci// 7.25.3.5
114bf215546Sopenharmony_ciint
115bf215546Sopenharmony_cicnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)
116bf215546Sopenharmony_ci{
117bf215546Sopenharmony_ci    int rt;
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci    assert(mtx != NULL);
120bf215546Sopenharmony_ci    assert(cond != NULL);
121bf215546Sopenharmony_ci    assert(abs_time != NULL);
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci    rt = pthread_cond_timedwait(cond, mtx, abs_time);
124bf215546Sopenharmony_ci    if (rt == ETIMEDOUT)
125bf215546Sopenharmony_ci        return thrd_timedout;
126bf215546Sopenharmony_ci    return (rt == 0) ? thrd_success : thrd_error;
127bf215546Sopenharmony_ci}
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci// 7.25.3.6
130bf215546Sopenharmony_ciint
131bf215546Sopenharmony_cicnd_wait(cnd_t *cond, mtx_t *mtx)
132bf215546Sopenharmony_ci{
133bf215546Sopenharmony_ci    assert(mtx != NULL);
134bf215546Sopenharmony_ci    assert(cond != NULL);
135bf215546Sopenharmony_ci    return (pthread_cond_wait(cond, mtx) == 0) ? thrd_success : thrd_error;
136bf215546Sopenharmony_ci}
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci/*-------------------- 7.25.4 Mutex functions --------------------*/
140bf215546Sopenharmony_ci// 7.25.4.1
141bf215546Sopenharmony_civoid
142bf215546Sopenharmony_cimtx_destroy(mtx_t *mtx)
143bf215546Sopenharmony_ci{
144bf215546Sopenharmony_ci    assert(mtx != NULL);
145bf215546Sopenharmony_ci    pthread_mutex_destroy(mtx);
146bf215546Sopenharmony_ci}
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci/*
149bf215546Sopenharmony_ci * XXX: Workaround when building with -O0 and without pthreads link.
150bf215546Sopenharmony_ci *
151bf215546Sopenharmony_ci * In such cases constant folding and dead code elimination won't be
152bf215546Sopenharmony_ci * available, thus the compiler will always add the pthread_mutexattr*
153bf215546Sopenharmony_ci * functions into the binary. As we try to link, we'll fail as the
154bf215546Sopenharmony_ci * symbols are unresolved.
155bf215546Sopenharmony_ci *
156bf215546Sopenharmony_ci * Ideally we'll enable the optimisations locally, yet that does not
157bf215546Sopenharmony_ci * seem to work.
158bf215546Sopenharmony_ci *
159bf215546Sopenharmony_ci * So the alternative workaround is to annotate the symbols as weak.
160bf215546Sopenharmony_ci * Thus the linker will be happy and things don't clash when building
161bf215546Sopenharmony_ci * with -O1 or greater.
162bf215546Sopenharmony_ci */
163bf215546Sopenharmony_ci#if defined(HAVE_FUNC_ATTRIBUTE_WEAK) && !defined(__CYGWIN__)
164bf215546Sopenharmony_ci__attribute__((weak))
165bf215546Sopenharmony_ciint pthread_mutexattr_init(pthread_mutexattr_t *attr);
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci__attribute__((weak))
168bf215546Sopenharmony_ciint pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci__attribute__((weak))
171bf215546Sopenharmony_ciint pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
172bf215546Sopenharmony_ci#endif
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci// 7.25.4.2
175bf215546Sopenharmony_ciint
176bf215546Sopenharmony_cimtx_init(mtx_t *mtx, int type)
177bf215546Sopenharmony_ci{
178bf215546Sopenharmony_ci    pthread_mutexattr_t attr;
179bf215546Sopenharmony_ci    assert(mtx != NULL);
180bf215546Sopenharmony_ci    if (type != mtx_plain && type != mtx_timed && type != mtx_try
181bf215546Sopenharmony_ci      && type != (mtx_plain|mtx_recursive)
182bf215546Sopenharmony_ci      && type != (mtx_timed|mtx_recursive)
183bf215546Sopenharmony_ci      && type != (mtx_try|mtx_recursive))
184bf215546Sopenharmony_ci        return thrd_error;
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci    if ((type & mtx_recursive) == 0) {
187bf215546Sopenharmony_ci        pthread_mutex_init(mtx, NULL);
188bf215546Sopenharmony_ci        return thrd_success;
189bf215546Sopenharmony_ci    }
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci    pthread_mutexattr_init(&attr);
192bf215546Sopenharmony_ci    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
193bf215546Sopenharmony_ci    pthread_mutex_init(mtx, &attr);
194bf215546Sopenharmony_ci    pthread_mutexattr_destroy(&attr);
195bf215546Sopenharmony_ci    return thrd_success;
196bf215546Sopenharmony_ci}
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci// 7.25.4.3
199bf215546Sopenharmony_ciint
200bf215546Sopenharmony_cimtx_lock(mtx_t *mtx)
201bf215546Sopenharmony_ci{
202bf215546Sopenharmony_ci    assert(mtx != NULL);
203bf215546Sopenharmony_ci    return (pthread_mutex_lock(mtx) == 0) ? thrd_success : thrd_error;
204bf215546Sopenharmony_ci}
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci// 7.25.4.4
207bf215546Sopenharmony_ciint
208bf215546Sopenharmony_cimtx_timedlock(mtx_t *mtx, const struct timespec *ts)
209bf215546Sopenharmony_ci{
210bf215546Sopenharmony_ci    assert(mtx != NULL);
211bf215546Sopenharmony_ci    assert(ts != NULL);
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci    {
214bf215546Sopenharmony_ci#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
215bf215546Sopenharmony_ci    int rt;
216bf215546Sopenharmony_ci    rt = pthread_mutex_timedlock(mtx, ts);
217bf215546Sopenharmony_ci    if (rt == 0)
218bf215546Sopenharmony_ci        return thrd_success;
219bf215546Sopenharmony_ci    return (rt == ETIMEDOUT) ? thrd_timedout : thrd_error;
220bf215546Sopenharmony_ci#else
221bf215546Sopenharmony_ci    time_t expire = time(NULL);
222bf215546Sopenharmony_ci    expire += ts->tv_sec;
223bf215546Sopenharmony_ci    while (mtx_trylock(mtx) != thrd_success) {
224bf215546Sopenharmony_ci        time_t now = time(NULL);
225bf215546Sopenharmony_ci        if (expire < now)
226bf215546Sopenharmony_ci            return thrd_timedout;
227bf215546Sopenharmony_ci        // busy loop!
228bf215546Sopenharmony_ci        thrd_yield();
229bf215546Sopenharmony_ci    }
230bf215546Sopenharmony_ci    return thrd_success;
231bf215546Sopenharmony_ci#endif
232bf215546Sopenharmony_ci    }
233bf215546Sopenharmony_ci}
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci// 7.25.4.5
236bf215546Sopenharmony_ciint
237bf215546Sopenharmony_cimtx_trylock(mtx_t *mtx)
238bf215546Sopenharmony_ci{
239bf215546Sopenharmony_ci    assert(mtx != NULL);
240bf215546Sopenharmony_ci    return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
241bf215546Sopenharmony_ci}
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci// 7.25.4.6
244bf215546Sopenharmony_ciint
245bf215546Sopenharmony_cimtx_unlock(mtx_t *mtx)
246bf215546Sopenharmony_ci{
247bf215546Sopenharmony_ci    assert(mtx != NULL);
248bf215546Sopenharmony_ci    return (pthread_mutex_unlock(mtx) == 0) ? thrd_success : thrd_error;
249bf215546Sopenharmony_ci}
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci/*------------------- 7.25.5 Thread functions -------------------*/
253bf215546Sopenharmony_ci// 7.25.5.1
254bf215546Sopenharmony_ciint
255bf215546Sopenharmony_cithrd_create(thrd_t *thr, thrd_start_t func, void *arg)
256bf215546Sopenharmony_ci{
257bf215546Sopenharmony_ci    struct impl_thrd_param *pack;
258bf215546Sopenharmony_ci    assert(thr != NULL);
259bf215546Sopenharmony_ci    pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param));
260bf215546Sopenharmony_ci    if (!pack) return thrd_nomem;
261bf215546Sopenharmony_ci    pack->func = func;
262bf215546Sopenharmony_ci    pack->arg = arg;
263bf215546Sopenharmony_ci    if (pthread_create(thr, NULL, impl_thrd_routine, pack) != 0) {
264bf215546Sopenharmony_ci        free(pack);
265bf215546Sopenharmony_ci        return thrd_error;
266bf215546Sopenharmony_ci    }
267bf215546Sopenharmony_ci    return thrd_success;
268bf215546Sopenharmony_ci}
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci// 7.25.5.2
271bf215546Sopenharmony_cithrd_t
272bf215546Sopenharmony_cithrd_current(void)
273bf215546Sopenharmony_ci{
274bf215546Sopenharmony_ci    return pthread_self();
275bf215546Sopenharmony_ci}
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci// 7.25.5.3
278bf215546Sopenharmony_ciint
279bf215546Sopenharmony_cithrd_detach(thrd_t thr)
280bf215546Sopenharmony_ci{
281bf215546Sopenharmony_ci    return (pthread_detach(thr) == 0) ? thrd_success : thrd_error;
282bf215546Sopenharmony_ci}
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci// 7.25.5.4
285bf215546Sopenharmony_ciint
286bf215546Sopenharmony_cithrd_equal(thrd_t thr0, thrd_t thr1)
287bf215546Sopenharmony_ci{
288bf215546Sopenharmony_ci    return pthread_equal(thr0, thr1);
289bf215546Sopenharmony_ci}
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci// 7.25.5.5
292bf215546Sopenharmony_ci_Noreturn
293bf215546Sopenharmony_civoid
294bf215546Sopenharmony_cithrd_exit(int res)
295bf215546Sopenharmony_ci{
296bf215546Sopenharmony_ci    pthread_exit((void*)(intptr_t)res);
297bf215546Sopenharmony_ci}
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci// 7.25.5.6
300bf215546Sopenharmony_ciint
301bf215546Sopenharmony_cithrd_join(thrd_t thr, int *res)
302bf215546Sopenharmony_ci{
303bf215546Sopenharmony_ci    void *code;
304bf215546Sopenharmony_ci    if (pthread_join(thr, &code) != 0)
305bf215546Sopenharmony_ci        return thrd_error;
306bf215546Sopenharmony_ci    if (res)
307bf215546Sopenharmony_ci        *res = (int)(intptr_t)code;
308bf215546Sopenharmony_ci    return thrd_success;
309bf215546Sopenharmony_ci}
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci// 7.25.5.7
312bf215546Sopenharmony_ciint
313bf215546Sopenharmony_cithrd_sleep(const struct timespec *time_point, struct timespec *remaining)
314bf215546Sopenharmony_ci{
315bf215546Sopenharmony_ci    assert(time_point != NULL);
316bf215546Sopenharmony_ci    return nanosleep(time_point, remaining);
317bf215546Sopenharmony_ci}
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci// 7.25.5.8
320bf215546Sopenharmony_civoid
321bf215546Sopenharmony_cithrd_yield(void)
322bf215546Sopenharmony_ci{
323bf215546Sopenharmony_ci    sched_yield();
324bf215546Sopenharmony_ci}
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci/*----------- 7.25.6 Thread-specific storage functions -----------*/
328bf215546Sopenharmony_ci// 7.25.6.1
329bf215546Sopenharmony_ciint
330bf215546Sopenharmony_citss_create(tss_t *key, tss_dtor_t dtor)
331bf215546Sopenharmony_ci{
332bf215546Sopenharmony_ci    assert(key != NULL);
333bf215546Sopenharmony_ci    return (pthread_key_create(key, dtor) == 0) ? thrd_success : thrd_error;
334bf215546Sopenharmony_ci}
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci// 7.25.6.2
337bf215546Sopenharmony_civoid
338bf215546Sopenharmony_citss_delete(tss_t key)
339bf215546Sopenharmony_ci{
340bf215546Sopenharmony_ci    pthread_key_delete(key);
341bf215546Sopenharmony_ci}
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci// 7.25.6.3
344bf215546Sopenharmony_civoid *
345bf215546Sopenharmony_citss_get(tss_t key)
346bf215546Sopenharmony_ci{
347bf215546Sopenharmony_ci    return pthread_getspecific(key);
348bf215546Sopenharmony_ci}
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci// 7.25.6.4
351bf215546Sopenharmony_ciint
352bf215546Sopenharmony_citss_set(tss_t key, void *val)
353bf215546Sopenharmony_ci{
354bf215546Sopenharmony_ci    return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error;
355bf215546Sopenharmony_ci}
356