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 
41 void
42 call_once(once_flag *flag, void (*func)(void))
43 {
44  pthread_once(flag, func);
45 }
46 
47 int
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 
58 void
60 {
61  pthread_cond_destroy(cond);
62 }
63 
64 int
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 
75 int
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 
86 int
87 cnd_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 
99 int
100 cnd_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 
112 void
114 {
115  pthread_mutex_destroy(mtx);
116 }
117 
118 int
119 mtx_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 
141 error_mutex_init:
142 error_mutexattr_settype:
143  pthread_mutexattr_destroy(&attr);
144 error_mutexattr_init:
145  errno = errsv;
146  return thrd_error;
147 }
148 
149 int
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 
162 int
163 mtx_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 
175 int
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 
188 int
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 
199 int
200 thrd_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 
217 thrd_t
219 {
220  return pthread_self();
221 }
222 
223 int
225 {
226  int errsv = pthread_detach(thr);
227  if (errsv) {
228  errno = errsv;
229  return thrd_error;
230  }
231  return thrd_success;
232 }
233 
234 int
236 {
237  return pthread_equal(thr0, thr1);
238 }
239 
240 _Noreturn void
241 thrd_exit(int res)
242 {
243  pthread_exit((void *)(intptr_t)res);
244  // cppcheck-suppress unreachableCode
245  for (;;)
246  ;
247 }
248 
249 int
250 thrd_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 
263 int
264 thrd_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
276 void
277 thrd_yield(void)
278 {
279  SwitchToThread();
280 }
281 #elif LELY_HAVE_SCHED
282 void
284 {
285  sched_yield();
286 }
287 #endif
288 
289 int
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 
300 void
302 {
303  pthread_key_delete(key);
304 }
305 
306 void *
308 {
309  return pthread_getspecific(key);
310 }
311 
312 int
313 tss_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
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...
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...
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_broadcast(cnd_t *cond)
Unblocks all of the threads that are blocked on the condition variable at cond at the time of the cal...
Indicates that the requested operation failed because a resource requested by a test and return funct...
Definition: threads.h:133
A mutex type that supports recursive locking.
Definition: threads.h:111
int thrd_equal(thrd_t thr0, thrd_t thr1)
Determines whether the thread identified by thr0 refers to the thread identified by thr1...
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 mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
void cnd_destroy(cnd_t *cond)
Releases all resources used by the condition variable at cond.
pthread_t thrd_t
A complete object type that holds an identifier for a thread.
Definition: threads.h:85
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...
Indicates that the time specified in the call was reached without acquiring the requested resource...
Definition: threads.h:128
Indicates that the requested operation succeeded.
Definition: threads.h:121
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: ...
pthread_key_t tss_t
A complete object type that holds an identifier for a thread-specific storage pointer.
Definition: threads.h:95
thrd_t thrd_current(void)
Identifies the thread that called it.
This header file is part of the C11 and POSIX compatibility library; it includes <threads.h>, if it exists, and defines any missing functionality.
pthread_cond_t cnd_t
A complete object type that holds an identifier for a condition variable.
Definition: threads.h:78
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
Definition: threads.h:102
int mtx_trylock(mtx_t *mtx)
Endeavors to lock the mutex at mtx.
void *(* thrd_start_t)(void *)
The function pointer type that is passed to thrd_create() to create a new thread. ...
Definition: threads.h:168
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 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...
pthread_once_t once_flag
A complete object type that holds a flag for use by call_once().
Definition: threads.h:143
Indicates that the requested operation failed because it was unable to allocate memory.
Definition: threads.h:138
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
Creates a new thread executing func(arg).
int thrd_detach(thrd_t thr)
Tells the operating system to dispose of any resources allocated to the thread identified by thr when...
int tss_create(tss_t *key, tss_dtor_t dtor)
Creates a thread-specific storage pointer with destructor dtor, which may be NULL.
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...
This header file is part of the C11 and POSIX compatibility library; it includes <stdint.h> and defines any missing functionality.
Indicates that the requested operation failed.
Definition: threads.h:123
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
void tss_delete(tss_t key)
Releases any resources used by the thread-specific storage identified by key.
#define _Noreturn
A function declared with a _Noreturn function specifier SHALL not return to its caller.
Definition: features.h:214
void * tss_get(tss_t key)
Returns the value for the current thread held in the thread-specific storage identified by key...
_Noreturn void thrd_exit(int res)
Terminates execution of the calling thread and sets its result code to res.
This is the internal header file of the C11 and POSIX compatibility library.
int cnd_init(cnd_t *cond)
Creates a condition variable.
void thrd_yield(void)
Endeavors to permit other threads to run, even if the current thread would ordinarily continue to run...
void(* tss_dtor_t)(void *)
The function pointer type used for a destructor for a thread-specific storage pointer.
Definition: threads.h:157