Lely core libraries 2.3.4
threads-pthread.c
Go to the documentation of this file.
1
23#include "libc.h"
24#include <lely/libc/threads.h>
25
26#if !LELY_NO_THREADS && LELY_HAVE_PTHREAD_H
27
28#if LELY_NO_ERRNO
29#error This file requires errno.
30#endif
31
32#include <errno.h>
33#include <stdint.h>
34
35#if _WIN32
36#include <processthreadsapi.h>
37#endif
38
39#undef LELY_HAVE_SCHED
40#if _POSIX_C_SOURCE >= 200112L && defined(_POSIX_PRIORITY_SCHEDULING)
41#define LELY_HAVE_SCHED 1
42#include <sched.h>
43#endif
44
45void
46call_once(once_flag *flag, void (*func)(void))
47{
48 pthread_once(flag, func);
49}
50
51int
52cnd_broadcast(cnd_t *cond)
53{
54 int errsv = pthread_cond_broadcast(cond);
55 if (errsv) {
56 errno = errsv;
57 return thrd_error;
58 }
59 return thrd_success;
60}
61
62void
63cnd_destroy(cnd_t *cond)
64{
65 pthread_cond_destroy(cond);
66}
67
68int
69cnd_init(cnd_t *cond)
70{
71 int errsv = pthread_cond_init(cond, NULL);
72 if (errsv) {
73 errno = errsv;
74 return errsv == ENOMEM ? thrd_nomem : thrd_error;
75 }
76 return thrd_success;
77}
78
79int
80cnd_signal(cnd_t *cond)
81{
82 int errsv = pthread_cond_signal(cond);
83 if (errsv) {
84 errno = errsv;
85 return thrd_error;
86 }
87 return thrd_success;
88}
89
90int
91cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
92{
93 int errsv = pthread_cond_timedwait(cond, mtx, ts);
94 if (errsv) {
95 errno = errsv;
96 return errsv == ETIMEDOUT ? thrd_timedout : thrd_error;
97 }
98 return thrd_success;
99}
100
101int
102cnd_wait(cnd_t *cond, mtx_t *mtx)
103{
104 int errsv = pthread_cond_wait(cond, mtx);
105 if (errsv) {
106 errno = errsv;
107 return thrd_error;
108 }
109 return thrd_success;
110}
111
112void
113mtx_destroy(mtx_t *mtx)
114{
115 pthread_mutex_destroy(mtx);
116}
117
118int
119mtx_init(mtx_t *mtx, int type)
120{
121 int errsv;
122 pthread_mutexattr_t attr;
123
124 errsv = pthread_mutexattr_init(&attr);
125 if (errsv)
126 goto error_mutexattr_init;
127 // clang-format off
128 errsv = pthread_mutexattr_settype(&attr, (type & mtx_recursive)
129 ? PTHREAD_MUTEX_RECURSIVE
130 : PTHREAD_MUTEX_NORMAL);
131 // clang-format on
132 if (errsv)
133 goto error_mutexattr_settype;
134 errsv = pthread_mutex_init(mtx, &attr);
135 if (errsv)
136 goto error_mutex_init;
137 pthread_mutexattr_destroy(&attr);
138
139 return thrd_success;
140
141error_mutex_init:
142error_mutexattr_settype:
143 pthread_mutexattr_destroy(&attr);
144error_mutexattr_init:
145 errno = errsv;
146 return thrd_error;
147}
148
149int
150mtx_lock(mtx_t *mtx)
151{
152 int errsv = pthread_mutex_lock(mtx);
153 if (errsv) {
154 errno = errsv;
155 return thrd_error;
156 }
157 return thrd_success;
158}
159
160int
161mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
162{
163 int errsv = pthread_mutex_timedlock(mtx, ts);
164 if (errsv) {
165 errno = errsv;
166 return errsv == ETIMEDOUT ? thrd_timedout : thrd_error;
167 }
168 return thrd_success;
169}
170
171int
172mtx_trylock(mtx_t *mtx)
173{
174 int errsv = pthread_mutex_trylock(mtx);
175 if (errsv) {
176 errno = errsv;
177 return errsv == EBUSY ? thrd_busy : thrd_error;
178 }
179 return thrd_success;
180}
181
182int
183mtx_unlock(mtx_t *mtx)
184{
185 int errsv = pthread_mutex_unlock(mtx);
186 if (errsv) {
187 errno = errsv;
188 return thrd_error;
189 }
190 return thrd_success;
191}
192
193int
194thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
195{
196#if __GNUC__ >= 8
197#pragma GCC diagnostic push
198#pragma GCC diagnostic ignored "-Wcast-function-type"
199#endif
200 int errsv = pthread_create(thr, NULL, (void *(*)(void *))func, arg);
201#if __GNUC__ >= 8
202#pragma GCC diagnostic pop
203#endif
204 if (errsv) {
205 errno = errsv;
206 return errsv == EAGAIN ? thrd_nomem : thrd_error;
207 }
208 return thrd_success;
209}
210
211thrd_t
212thrd_current(void)
213{
214 return pthread_self();
215}
216
217int
218thrd_detach(thrd_t thr)
219{
220 int errsv = pthread_detach(thr);
221 if (errsv) {
222 errno = errsv;
223 return thrd_error;
224 }
225 return thrd_success;
226}
227
228int
229thrd_equal(thrd_t thr0, thrd_t thr1)
230{
231 return pthread_equal(thr0, thr1);
232}
233
234_Noreturn void
235thrd_exit(int res)
236{
237 pthread_exit((void *)(intptr_t)res);
238 // cppcheck-suppress unreachableCode
239 for (;;)
240 ;
241}
242
243int
244thrd_join(thrd_t thr, int *res)
245{
246 void *value_ptr = NULL;
247 int errsv = pthread_join((pthread_t)thr, &value_ptr);
248 if (errsv) {
249 errno = errsv;
250 return thrd_error;
251 }
252 if (res)
253 *res = (intptr_t)value_ptr;
254 return thrd_success;
255}
256
257int
258thrd_sleep(const struct timespec *duration, struct timespec *remaining)
259{
260 int errsv = errno;
261 int res = nanosleep(duration, remaining);
262 if (res) {
263 res = errno == EINTR ? -1 : -2;
264 errno = errsv;
265 }
266 return res;
267}
268
269#if _WIN32
270void
271thrd_yield(void)
272{
273 SwitchToThread();
274}
275#elif LELY_HAVE_SCHED
276void
277thrd_yield(void)
278{
279 sched_yield();
280}
281#endif
282
283int
284tss_create(tss_t *key, tss_dtor_t dtor)
285{
286 int errsv = pthread_key_create(key, dtor);
287 if (errsv) {
288 errno = errsv;
289 return thrd_error;
290 }
291 return thrd_success;
292}
293
294void
295tss_delete(tss_t key)
296{
297 pthread_key_delete(key);
298}
299
300void *
301tss_get(tss_t key)
302{
303 return pthread_getspecific(key);
304}
305
306int
307tss_set(tss_t key, void *val)
308{
309 int errsv = pthread_setspecific(key, val);
310 if (errsv) {
311 errno = errsv;
312 return thrd_error;
313 }
314 return thrd_success;
315}
316
317#endif // !LELY_NO_THREADS && LELY_HAVE_PTHREAD_H
#define _Noreturn
A function declared with a _Noreturn function specifier SHALL not return to its caller.
Definition features.h:224
This is the internal header file of the C11 and POSIX compatibility library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdint....
A time type with nanosecond resolution.
Definition time.h:88
This header file is part of the C11 and POSIX compatibility library; it includes <threads....
int cnd_init(cnd_t *cond)
Creates a condition variable.
int(* thrd_start_t)(void *)
A complete object type that holds a flag for use by call_once().
Definition threads.h:168
int thrd_equal(thrd_t thr0, thrd_t thr1)
Determines whether the thread identified by thr0 refers to the thread identified by thr1.
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
Creates a new thread executing func(arg).
int tss_create(tss_t *key, tss_dtor_t dtor)
Creates a thread-specific storage pointer with destructor dtor, which may be NULL.
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
Atomically unlocks the mutex at mtx and endeavors to block until the condition variable at cond is si...
_Noreturn void thrd_exit(int res)
Terminates execution of the calling thread and sets its result code to res.
void * tss_get(tss_t key)
Returns the value for the current thread held in the thread-specific storage identified by key.
int tss_set(tss_t key, void *val)
Sets the value for the current thread held in the thread-specific storage identified by key to val.
int cnd_broadcast(cnd_t *cond)
Unblocks all of the threads that are blocked on the condition variable at cond at the time of the cal...
int thrd_sleep(const struct timespec *duration, struct timespec *remaining)
Suspends execution of the calling thread until either the interval specified by duration has elapsed ...
int mtx_init(mtx_t *mtx, int type)
Creates a mutex object with properties indicated by type, which must have one of the four values:
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
int mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
Endeavors to block until it locks the mutex at mtx or until after the TIME_UTC-based calendar time at...
int thrd_join(thrd_t thr, int *res)
Joins the thread identified by thr with the current thread by blocking until the other thread has ter...
void cnd_destroy(cnd_t *cond)
Releases all resources used by the condition variable at cond.
thrd_t thrd_current(void)
Identifies the thread that called it.
void call_once(once_flag *flag, void(*func)(void))
Uses the #once_flag at flag to ensure that func is called exactly once, the first time the call_once(...
int cnd_wait(cnd_t *cond, mtx_t *mtx)
Atomically unlocks the mutex at mtx and endeavors to block until the condition variable at cond is si...
int mtx_trylock(mtx_t *mtx)
Endeavors to lock the mutex at mtx.
void thrd_yield(void)
Endeavors to permit other threads to run, even if the current thread would ordinarily continue to run...
int thrd_detach(thrd_t thr)
Tells the operating system to dispose of any resources allocated to the thread identified by thr when...
@ thrd_timedout
Indicates that the time specified in the call was reached without acquiring the requested resource.
Definition threads.h:128
@ thrd_success
Indicates that the requested operation succeeded.
Definition threads.h:121
@ thrd_busy
Indicates that the requested operation failed because a resource requested by a test and return funct...
Definition threads.h:133
@ thrd_nomem
Indicates that the requested operation failed because it was unable to allocate memory.
Definition threads.h:138
@ thrd_error
Indicates that the requested operation failed.
Definition threads.h:123
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
void tss_delete(tss_t key)
Releases any resources used by the thread-specific storage identified by key.
int cnd_signal(cnd_t *cond)
Unblocks one of the threads that are blocked on the condition variable at cond at the time of the cal...
@ mtx_recursive
A mutex type that supports recursive locking.
Definition threads.h:111