Lely core libraries 1.9.2
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#include <errno.h>
29#include <stdint.h>
30
31#if _WIN32
32#include <processthreadsapi.h>
33#endif
34
35#undef LELY_HAVE_SCHED
36#if _POSIX_C_SOURCE >= 200112L && defined(_POSIX_PRIORITY_SCHEDULING)
37#define LELY_HAVE_SCHED 1
38#include <sched.h>
39#endif
40
41void
42call_once(once_flag *flag, void (*func)(void))
43{
44 pthread_once(flag, func);
45}
46
47int
48cnd_broadcast(cnd_t *cond)
49{
50 int errsv = pthread_cond_broadcast(cond);
51 if (errsv) {
52 errno = errsv;
53 return thrd_error;
54 }
55 return thrd_success;
56}
57
58void
59cnd_destroy(cnd_t *cond)
60{
61 pthread_cond_destroy(cond);
62}
63
64int
65cnd_init(cnd_t *cond)
66{
67 int errsv = pthread_cond_init(cond, NULL);
68 if (errsv) {
69 errno = errsv;
70 return errsv == ENOMEM ? thrd_nomem : thrd_error;
71 }
72 return thrd_success;
73}
74
75int
76cnd_signal(cnd_t *cond)
77{
78 int errsv = pthread_cond_signal(cond);
79 if (errsv) {
80 errno = errsv;
81 return thrd_error;
82 }
83 return thrd_success;
84}
85
86int
87cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
88{
89 int errsv;
90 while ((errsv = pthread_cond_timedwait(cond, mtx, ts)) == EINTR)
91 ;
92 if (errsv) {
93 errno = errsv;
94 return errsv == ETIMEDOUT ? thrd_timedout : thrd_error;
95 }
96 return thrd_success;
97}
98
99int
100cnd_wait(cnd_t *cond, mtx_t *mtx)
101{
102 int errsv;
103 while ((errsv = pthread_cond_wait(cond, mtx)) == EINTR)
104 ;
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;
153 while ((errsv = pthread_mutex_lock(mtx)) == EINTR)
154 ;
155 if (errsv) {
156 errno = errsv;
157 return thrd_error;
158 }
159 return thrd_success;
160}
161
162int
163mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
164{
165 int errsv;
166 while ((errsv = pthread_mutex_timedlock(mtx, ts)) == EINTR)
167 ;
168 if (errsv) {
169 errno = errsv;
170 return errsv == ETIMEDOUT ? thrd_timedout : thrd_error;
171 }
172 return thrd_success;
173}
174
175int
176mtx_trylock(mtx_t *mtx)
177{
178 int errsv;
179 while ((errsv = pthread_mutex_trylock(mtx)) == EINTR)
180 ;
181 if (errsv) {
182 errno = errsv;
183 return errsv == EBUSY ? thrd_busy : thrd_error;
184 }
185 return thrd_success;
186}
187
188int
189mtx_unlock(mtx_t *mtx)
190{
191 int errsv = pthread_mutex_unlock(mtx);
192 if (errsv) {
193 errno = errsv;
194 return thrd_error;
195 }
196 return thrd_success;
197}
198
199int
200thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
201{
202#if __GNUC__ >= 8
203#pragma GCC diagnostic push
204#pragma GCC diagnostic ignored "-Wcast-function-type"
205#endif
206 int errsv = pthread_create(thr, NULL, (void *(*)(void *))func, arg);
207#if __GNUC__ >= 8
208#pragma GCC diagnostic pop
209#endif
210 if (errsv) {
211 errno = errsv;
212 return errsv == EAGAIN ? thrd_nomem : thrd_error;
213 }
214 return thrd_success;
215}
216
217thrd_t
218thrd_current(void)
219{
220 return pthread_self();
221}
222
223int
224thrd_detach(thrd_t thr)
225{
226 int errsv = pthread_detach(thr);
227 if (errsv) {
228 errno = errsv;
229 return thrd_error;
230 }
231 return thrd_success;
232}
233
234int
235thrd_equal(thrd_t thr0, thrd_t thr1)
236{
237 return pthread_equal(thr0, thr1);
238}
239
240_Noreturn void
241thrd_exit(int res)
242{
243 pthread_exit((void *)(intptr_t)res);
244 // cppcheck-suppress unreachableCode
245 for (;;)
246 ;
247}
248
249int
250thrd_join(thrd_t thr, int *res)
251{
252 void *value_ptr = NULL;
253 int errsv = pthread_join((pthread_t)thr, &value_ptr);
254 if (errsv) {
255 errno = errsv;
256 return thrd_error;
257 }
258 if (res)
259 *res = (intptr_t)value_ptr;
260 return thrd_success;
261}
262
263int
264thrd_sleep(const struct timespec *duration, struct timespec *remaining)
265{
266 int errsv = errno;
267 int res = nanosleep(duration, remaining);
268 if (res) {
269 res = errno == EINTR ? -1 : -2;
270 errno = errsv;
271 }
272 return res;
273}
274
275#if _WIN32
276void
277thrd_yield(void)
278{
279 SwitchToThread();
280}
281#elif LELY_HAVE_SCHED
282void
283thrd_yield(void)
284{
285 sched_yield();
286}
287#endif
288
289int
290tss_create(tss_t *key, tss_dtor_t dtor)
291{
292 int errsv = pthread_key_create(key, dtor);
293 if (errsv) {
294 errno = errsv;
295 return thrd_error;
296 }
297 return thrd_success;
298}
299
300void
301tss_delete(tss_t key)
302{
303 pthread_key_delete(key);
304}
305
306void *
307tss_get(tss_t key)
308{
309 return pthread_getspecific(key);
310}
311
312int
313tss_set(tss_t key, void *val)
314{
315 int errsv = pthread_setspecific(key, val);
316 if (errsv) {
317 errno = errsv;
318 return thrd_error;
319 }
320 return thrd_success;
321}
322
323#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:214
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:83
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_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...
void *(* thrd_start_t)(void *)
A complete object type that holds a flag for use by call_once().
Definition: threads.h:168
_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 ...
@ 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_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.
@ mtx_recursive
A mutex type that supports recursive locking.
Definition: threads.h:111
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...