libsidplayfp  2.0.2
c11threads.h
1 /*
2 Author: John Tsiombikas <nuclear@member.fsf.org>
3 
4 I place this piece of code in the public domain. Feel free to use as you see
5 fit. I'd appreciate it if you keep my name at the top of the code somehwere,
6 but whatever.
7 
8 Main project site: https://github.com/jtsiomb/c11threads
9 */
10 
11 /* TODO: port to MacOSX: no timed mutexes under macosx...
12  * just delete that bit if you don't care about timed mutexes
13  */
14 
15 #ifndef C11THREADS_H_
16 #define C11THREADS_H_
17 
18 #include <time.h>
19 #include <errno.h>
20 #include <pthread.h>
21 #include <sched.h> /* for sched_yield */
22 #include <sys/time.h>
23 
24 #define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
25 
26 /* types */
27 typedef pthread_t thrd_t;
28 typedef pthread_mutex_t mtx_t;
29 typedef pthread_cond_t cnd_t;
30 typedef pthread_key_t tss_t;
31 typedef pthread_once_t once_flag;
32 
33 typedef int (*thrd_start_t)(void*);
34 typedef void (*tss_dtor_t)(void*);
35 
36 
37 typedef struct {
38  time_t sec;
39  long nsec;
40 } xtime;
41 
42 enum {
43  mtx_plain = 0,
44  mtx_recursive = 1,
45  mtx_timed = 2,
46  mtx_try = 4
47 };
48 
49 enum {
50  thrd_success,
51  thrd_busy,
52  thrd_error,
53  thrd_nomem
54 };
55 
56 
57 /* ---- thread management ---- */
58 
59 static inline int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
60 {
61  /* XXX there's a third possible value returned according to the standard:
62  * thrd_nomem. but it doesn't seem to correspond to any pthread_create errors.
63  */
64  return pthread_create(thr, 0, (void*(*)(void*))func, arg) == 0 ? thrd_success : thrd_error;
65 }
66 
67 static inline void thrd_exit(int res)
68 {
69  pthread_exit((void*)(long)res);
70 }
71 
72 static inline int thrd_join(thrd_t thr, int *res)
73 {
74  void *retval;
75 
76  if(pthread_join(thr, &retval) != 0) {
77  return thrd_error;
78  }
79  if(res) {
80  *res = (long)retval;
81  }
82  return thrd_success;
83 }
84 
85 static inline int thrd_detach(thrd_t thr)
86 {
87  return pthread_detach(thr) == 0 ? thrd_success : thrd_error;
88 }
89 
90 static inline thrd_t thrd_current(void)
91 {
92  return pthread_self();
93 }
94 
95 static inline int thrd_equal(thrd_t a, thrd_t b)
96 {
97  return pthread_equal(a, b);
98 }
99 
100 static inline void thrd_sleep(const xtime *xt)
101 {
102  int res;
103  struct timespec ts;
104  ts.tv_sec = (long)xt->sec;
105  ts.tv_nsec = xt->nsec;
106 
107  do {
108  struct timespec rem;
109  res = nanosleep(&ts, &rem);
110  ts = rem;
111  } while(res == -1 && errno == EINTR);
112 }
113 
114 static inline void thrd_yield(void)
115 {
116  sched_yield();
117 }
118 
119 /* ---- mutexes ---- */
120 
121 static inline int mtx_init(mtx_t *mtx, int type)
122 {
123  int res;
124  pthread_mutexattr_t attr;
125 
126  pthread_mutexattr_init(&attr);
127 
128  /* XXX I don't think these are exactly correct semantics */
129  if(type & mtx_try) {
130  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
131  }
132 #if 0
133  if(type & mtx_timed) {
134  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP);
135  }
136 #endif
137  if(type & mtx_recursive) {
138  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
139  }
140 
141  res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error;
142  pthread_mutexattr_destroy(&attr);
143  return res;
144 }
145 
146 static inline void mtx_destroy(mtx_t *mtx)
147 {
148  pthread_mutex_destroy(mtx);
149 }
150 
151 static inline int mtx_lock(mtx_t *mtx)
152 {
153  int res = pthread_mutex_lock(mtx);
154  if(res == EDEADLK) {
155  return thrd_busy;
156  }
157  return res == 0 ? thrd_success : thrd_error;
158 }
159 
160 static inline int mtx_trylock(mtx_t *mtx)
161 {
162  int res = pthread_mutex_trylock(mtx);
163  if(res == EBUSY) {
164  return thrd_busy;
165  }
166  return res == 0 ? thrd_success : thrd_error;
167 }
168 #if 0
169 static inline int mtx_timedlock(mtx_t *mtx, const xtime *xt)
170 {
171  int res;
172  struct timespec ts;
173 
174  ts.tv_sec = (long)xt->sec;
175  ts.tv_nsec = xt->nsec;
176 
177  if((res = pthread_mutex_timedlock(mtx, &ts)) == EBUSY) {
178  return thrd_busy;
179  }
180  return res == 0 ? thrd_success : thrd_error;
181 }
182 #endif
183 static inline int mtx_unlock(mtx_t *mtx)
184 {
185  return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;
186 }
187 
188 /* ---- condition variables ---- */
189 
190 static inline int cnd_init(cnd_t *cond)
191 {
192  return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error;
193 }
194 
195 static inline void cnd_destroy(cnd_t *cond)
196 {
197  pthread_cond_destroy(cond);
198 }
199 
200 static inline int cnd_signal(cnd_t *cond)
201 {
202  return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
203 }
204 
205 static inline int cnd_broadcast(cnd_t *cond)
206 {
207  return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error;
208 }
209 
210 static inline int cnd_wait(cnd_t *cond, mtx_t *mtx)
211 {
212  return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
213 }
214 
215 static inline int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
216 {
217  int res;
218  struct timespec ts;
219 
220  ts.tv_sec = (long)xt->sec;
221  ts.tv_nsec = xt->nsec;
222 
223  if((res = pthread_cond_timedwait(cond, mtx, &ts)) != 0) {
224  return res == ETIMEDOUT ? thrd_busy : thrd_error;
225  }
226  return thrd_success;
227 }
228 
229 /* ---- thread-specific data ---- */
230 
231 static inline int tss_create(tss_t *key, tss_dtor_t dtor)
232 {
233  return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error;
234 }
235 
236 static inline void tss_delete(tss_t key)
237 {
238  pthread_key_delete(key);
239 }
240 
241 static inline int tss_set(tss_t key, void *val)
242 {
243  return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error;
244 }
245 
246 static inline void *tss_get(tss_t key)
247 {
248  return pthread_getspecific(key);
249 }
250 
251 /* ---- misc ---- */
252 
253 static inline void call_once(once_flag *flag, void (*func)(void))
254 {
255  pthread_once(flag, func);
256 }
257 
258 /* TODO take base into account */
259 static inline int xtime_get(xtime *xt, int base)
260 {
261  struct timeval tv;
262 
263  gettimeofday(&tv, 0);
264 
265  xt->sec = tv.tv_sec;
266  xt->nsec = tv.tv_usec * 1000;
267  return base;
268 }
269 
270 #endif /* C11THREADS_H_ */
xtime
Definition: c11threads.h:37