Lely core libraries  2.2.5
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 = pthread_cond_timedwait(cond, mtx, ts);
90  if (errsv) {
91  errno = errsv;
92  return errsv == ETIMEDOUT ? thrd_timedout : thrd_error;
93  }
94  return thrd_success;
95 }
96 
97 int
98 cnd_wait(cnd_t *cond, mtx_t *mtx)
99 {
100  int errsv = pthread_cond_wait(cond, mtx);
101  if (errsv) {
102  errno = errsv;
103  return thrd_error;
104  }
105  return thrd_success;
106 }
107 
108 void
110 {
111  pthread_mutex_destroy(mtx);
112 }
113 
114 int
115 mtx_init(mtx_t *mtx, int type)
116 {
117  int errsv;
118  pthread_mutexattr_t attr;
119 
120  errsv = pthread_mutexattr_init(&attr);
121  if (errsv)
122  goto error_mutexattr_init;
123  // clang-format off
124  errsv = pthread_mutexattr_settype(&attr, (type & mtx_recursive)
125  ? PTHREAD_MUTEX_RECURSIVE
126  : PTHREAD_MUTEX_NORMAL);
127  // clang-format on
128  if (errsv)
129  goto error_mutexattr_settype;
130  errsv = pthread_mutex_init(mtx, &attr);
131  if (errsv)
132  goto error_mutex_init;
133  pthread_mutexattr_destroy(&attr);
134 
135  return thrd_success;
136 
137 error_mutex_init:
138 error_mutexattr_settype:
139  pthread_mutexattr_destroy(&attr);
140 error_mutexattr_init:
141  errno = errsv;
142  return thrd_error;
143 }
144 
145 int
147 {
148  int errsv = pthread_mutex_lock(mtx);
149  if (errsv) {
150  errno = errsv;
151  return thrd_error;
152  }
153  return thrd_success;
154 }
155 
156 int
157 mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
158 {
159  int errsv = pthread_mutex_timedlock(mtx, ts);
160  if (errsv) {
161  errno = errsv;
162  return errsv == ETIMEDOUT ? thrd_timedout : thrd_error;
163  }
164  return thrd_success;
165 }
166 
167 int
169 {
170  int errsv = pthread_mutex_trylock(mtx);
171  if (errsv) {
172  errno = errsv;
173  return errsv == EBUSY ? thrd_busy : thrd_error;
174  }
175  return thrd_success;
176 }
177 
178 int
180 {
181  int errsv = pthread_mutex_unlock(mtx);
182  if (errsv) {
183  errno = errsv;
184  return thrd_error;
185  }
186  return thrd_success;
187 }
188 
189 int
190 thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
191 {
192 #if __GNUC__ >= 8
193 #pragma GCC diagnostic push
194 #pragma GCC diagnostic ignored "-Wcast-function-type"
195 #endif
196  int errsv = pthread_create(thr, NULL, (void *(*)(void *))func, arg);
197 #if __GNUC__ >= 8
198 #pragma GCC diagnostic pop
199 #endif
200  if (errsv) {
201  errno = errsv;
202  return errsv == EAGAIN ? thrd_nomem : thrd_error;
203  }
204  return thrd_success;
205 }
206 
207 thrd_t
209 {
210  return pthread_self();
211 }
212 
213 int
215 {
216  int errsv = pthread_detach(thr);
217  if (errsv) {
218  errno = errsv;
219  return thrd_error;
220  }
221  return thrd_success;
222 }
223 
224 int
226 {
227  return pthread_equal(thr0, thr1);
228 }
229 
230 _Noreturn void
231 thrd_exit(int res)
232 {
233  pthread_exit((void *)(intptr_t)res);
234  // cppcheck-suppress unreachableCode
235  for (;;)
236  ;
237 }
238 
239 int
240 thrd_join(thrd_t thr, int *res)
241 {
242  void *value_ptr = NULL;
243  int errsv = pthread_join((pthread_t)thr, &value_ptr);
244  if (errsv) {
245  errno = errsv;
246  return thrd_error;
247  }
248  if (res)
249  *res = (intptr_t)value_ptr;
250  return thrd_success;
251 }
252 
253 int
254 thrd_sleep(const struct timespec *duration, struct timespec *remaining)
255 {
256  int errsv = errno;
257  int res = nanosleep(duration, remaining);
258  if (res) {
259  res = errno == EINTR ? -1 : -2;
260  errno = errsv;
261  }
262  return res;
263 }
264 
265 #if _WIN32
266 void
267 thrd_yield(void)
268 {
269  SwitchToThread();
270 }
271 #elif LELY_HAVE_SCHED
272 void
274 {
275  sched_yield();
276 }
277 #endif
278 
279 int
281 {
282  int errsv = pthread_key_create(key, dtor);
283  if (errsv) {
284  errno = errsv;
285  return thrd_error;
286  }
287  return thrd_success;
288 }
289 
290 void
292 {
293  pthread_key_delete(key);
294 }
295 
296 void *
298 {
299  return pthread_getspecific(key);
300 }
301 
302 int
303 tss_set(tss_t key, void *val)
304 {
305  int errsv = pthread_setspecific(key, val);
306  if (errsv) {
307  errno = errsv;
308  return thrd_error;
309  }
310  return thrd_success;
311 }
312 
313 #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....
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.
void * tss_get(tss_t key)
Returns the value for the current thread held in the thread-specific storage identified by key.
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.
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