Libmacro  0.2
Libmacro is an extensible macro and hotkey library.
c11threads.h
Go to the documentation of this file.
1 /* Libmacro - A multi-platform, extendable macro and hotkey C library
2  Copyright (C) 2013 Jonathan Pelletier, New Paradigm Software
3  Adapted from c11threads.h by John Tsiombikas <nuclear@member.fsf.org>
4  Main project site: https://github.com/jtsiomb/c11threads
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
29 #ifndef MCR_UTIL_C11THREADS_H_
30 #define MCR_UTIL_C11THREADS_H_
31 
32 /* __STDC_NO_THREADS__ is 'not' defined, which means standard library 'does' have
33  threading. Defined this way causes problems, but such is the way of it. */
34 #ifndef __STDC_NO_THREADS__
35 
36 /* Windows does not have C threads, except maybe some newer MSVC...
37  Just be safe with it. __STDC_NO_THREADS__ is not defined, but Windows does not
38  have it anyways. */
39 #ifdef MCR_PLATFORM_WINDOWS
40  #include "mcr/util/cppthread.h"
41 #else
42  #include <threads.h>
43 #endif
44 
45 /* __STDC_NO_THREADS__ 'is' defined, which means the standard library 'does not' have
46  threading. */
47 #else
48 
49 #ifdef __cplusplus
50  #include <ctime>
51  #include <cerrno>
52 #else
53  #include <time.h>
54  #include <errno.h>
55 #endif
56 
57 #include <sys/time.h>
58 #include <pthread.h>
59 #include <sched.h> /* for sched_yield */
60 
61 #ifdef __cplusplus
62 extern "C" {
63 #endif
64 
65 #define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
66 
67 #ifdef __APPLE__
68 /* Darwin doesn't implement timed mutexes currently */
69 #define C11THREADS_NO_TIMED_MUTEX
70 #endif
71 
72 #ifdef C11THREADS_NO_TIMED_MUTEX
73 #define PTHREAD_MUTEX_TIMED_NP PTHREAD_MUTEX_NORMAL
74 #define C11THREADS_TIMEDLOCK_POLL_INTERVAL 5000000 /* 5 ms */
75 #endif
76 
77 /* types */
78 typedef pthread_t thrd_t;
79 typedef pthread_mutex_t mtx_t;
80 typedef pthread_cond_t cnd_t;
81 typedef pthread_key_t tss_t;
82 typedef pthread_once_t once_flag;
83 
84 typedef int (*thrd_start_t)(void *);
85 typedef void (*tss_dtor_t)(void *);
86 
87 enum {
88  mtx_plain = 0,
89  mtx_recursive = 1,
90  mtx_timed = 2
91 };
92 
93 enum {
94  thrd_success,
95  thrd_timedout,
96  thrd_busy,
97  thrd_error,
98  thrd_nomem
99 };
100 
101 /* ---- thread management ---- */
102 
103 static inline int thrd_create(thrd_t * thr, thrd_start_t func, void *arg)
104 {
105  /* XXX there's a third possible value returned according to the standard:
106  * thrd_nomem. but it doesn't seem to correspond to any pthread_create errors.
107  */
108  return pthread_create(thr, 0, (void *(*)(void *))func,
109  arg) == 0 ? thrd_success : thrd_error;
110 }
111 
112 static inline void thrd_exit(int res)
113 {
114  pthread_exit((void *)(long)res);
115 }
116 
117 static inline int thrd_join(thrd_t thr, int *res)
118 {
119  void *retval;
120 
121  if (pthread_join(thr, &retval) != 0) {
122  return thrd_error;
123  }
124  if (res) {
125  *res = (long)retval;
126  }
127  return thrd_success;
128 }
129 
130 static inline int thrd_detach(thrd_t thr)
131 {
132  return pthread_detach(thr) == 0 ? thrd_success : thrd_error;
133 }
134 
135 static inline thrd_t thrd_current(void)
136 {
137  return pthread_self();
138 }
139 
140 static inline int thrd_equal(thrd_t a, thrd_t b)
141 {
142  return pthread_equal(a, b);
143 }
144 
145 static inline void thrd_sleep(const struct timespec *ts_in,
146  struct timespec *rem_out)
147 {
148  int res;
149  struct timespec rem, ts = *ts_in;
150 
151  do {
152  res = nanosleep(&ts, &rem);
153  ts = rem;
154  } while (res == -1 && errno == EINTR);
155 
156  if (rem_out) {
157  *rem_out = rem;
158  }
159 }
160 
161 static inline void thrd_yield(void)
162 {
163  sched_yield();
164 }
165 
166 /* ---- mutexes ---- */
167 
168 static inline int mtx_init(mtx_t * mtx, int type)
169 {
170  int res;
171  pthread_mutexattr_t attr;
172 
173  pthread_mutexattr_init(&attr);
174 
175  if (type & mtx_timed) {
176  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP);
177  }
178  if (type & mtx_recursive) {
179  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
180  }
181 
182  res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error;
183  pthread_mutexattr_destroy(&attr);
184  return res;
185 }
186 
187 static inline void mtx_destroy(mtx_t * mtx)
188 {
189  pthread_mutex_destroy(mtx);
190 }
191 
192 static inline int mtx_lock(mtx_t * mtx)
193 {
194  int res = pthread_mutex_lock(mtx);
195  if (res == EDEADLK) {
196  return thrd_busy;
197  }
198  return res == 0 ? thrd_success : thrd_error;
199 }
200 
201 static inline int mtx_trylock(mtx_t * mtx)
202 {
203  int res = pthread_mutex_trylock(mtx);
204  if (res == EBUSY) {
205  return thrd_busy;
206  }
207  return res == 0 ? thrd_success : thrd_error;
208 }
209 
210 static inline int mtx_timedlock(mtx_t * mtx, const struct timespec *ts)
211 {
212  int res;
213 #ifdef C11THREADS_NO_TIMED_MUTEX
214  /* fake a timedlock by polling trylock in a loop and waiting for a bit */
215  struct timeval now;
216  struct timespec sleeptime;
217 
218  sleeptime.tv_sec = 0;
219  sleeptime.tv_nsec = C11THREADS_TIMEDLOCK_POLL_INTERVAL;
220 
221  while ((res = pthread_mutex_trylock(mtx)) == EBUSY) {
222  gettimeofday(&now, NULL);
223 
224  if (now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec &&
225  (now.tv_usec * 1000) >= ts->tv_nsec)) {
226  return thrd_timedout;
227  }
228 
229  nanosleep(&sleeptime, NULL);
230  }
231 #else
232  if ((res = pthread_mutex_timedlock(mtx, ts)) == ETIMEDOUT) {
233  return thrd_timedout;
234  }
235 #endif
236  return res == 0 ? thrd_success : thrd_error;
237 }
238 
239 static inline int mtx_unlock(mtx_t * mtx)
240 {
241  return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;
242 }
243 
244 /* ---- condition variables ---- */
245 
246 static inline int cnd_init(cnd_t * cond)
247 {
248  return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error;
249 }
250 
251 static inline void cnd_destroy(cnd_t * cond)
252 {
253  pthread_cond_destroy(cond);
254 }
255 
256 static inline int cnd_signal(cnd_t * cond)
257 {
258  return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
259 }
260 
261 static inline int cnd_broadcast(cnd_t * cond)
262 {
263  return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error;
264 }
265 
266 static inline int cnd_wait(cnd_t * cond, mtx_t * mtx)
267 {
268  return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
269 }
270 
271 static inline int cnd_timedwait(cnd_t * cond, mtx_t * mtx,
272  const struct timespec *ts)
273 {
274  int res;
275 
276  if ((res = pthread_cond_timedwait(cond, mtx, ts)) != 0) {
277  return res == ETIMEDOUT ? thrd_timedout : thrd_error;
278  }
279  return thrd_success;
280 }
281 
282 /* ---- thread-specific data ---- */
283 
284 static inline int tss_create(tss_t * key, tss_dtor_t dtor)
285 {
286  return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error;
287 }
288 
289 static inline void tss_delete(tss_t key)
290 {
291  pthread_key_delete(key);
292 }
293 
294 static inline int tss_set(tss_t key, void *val)
295 {
296  return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error;
297 }
298 
299 static inline void *tss_get(tss_t key)
300 {
301  return pthread_getspecific(key);
302 }
303 
304 /* ---- misc ---- */
305 
306 static inline void call_once(once_flag * flag, void (*func)(void))
307 {
308  pthread_once(flag, func);
309 }
310 
311 #ifdef __cplusplus
312 }
313 #endif
314 
315 #endif /* __STDC_NO_THREADS__ */
316 #endif /* MCR_UTIL_C11THREADS_H_ */
MCR_API int cnd_timedwait(cnd_t *cond, mtx_t *mutex, const struct timespec *time_point)
MCR_API int cnd_wait(cnd_t *cond, mtx_t *mutex)
#define dtor
Definition: defines.h:93