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
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
64{
65 pthread_cond_destroy(cond);
66}
67
68int
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
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
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
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
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
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
213{
214 return pthread_self();
215}
216
217int
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
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
278{
279 sched_yield();
280}
281#endif
282
283int
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
296{
297 pthread_key_delete(key);
298}
299
300void *
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....
int cnd_init(cnd_t *cond)
Creates a condition variable.
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...
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...
This header file is part of the C11 and POSIX compatibility library; it includes <threads....
pthread_key_t tss_t
A complete object type that holds an identifier for a thread-specific storage pointer.
Definition: threads.h:95
int(* thrd_start_t)(void *)
The function pointer type that is passed to thrd_create() to create a new thread.
Definition: threads.h:168
pthread_t thrd_t
A complete object type that holds an identifier for a thread.
Definition: threads.h:85
pthread_cond_t cnd_t
A complete object type that holds an identifier for a condition variable.
Definition: threads.h:78
pthread_once_t once_flag
A complete object type that holds a flag for use by call_once().
Definition: threads.h:143
@ 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
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
Definition: threads.h:102
@ mtx_recursive
A mutex type that supports recursive locking.
Definition: threads.h:111
void(* tss_dtor_t)(void *)
The function pointer type used for a destructor for a thread-specific storage pointer.
Definition: threads.h:157