c11threads

view c11threads.h @ 0:056c9db89e79

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 24 Sep 2012 12:32:42 +0300
parents
children
line source
1 #ifndef C11THREADS_H_
2 #define C11THREADS_H_
4 #include <time.h>
5 #include <errno.h>
6 #include <pthread.h>
7 #include <sched.h> /* for sched_yield */
8 #include <sys/time.h>
10 #define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
12 /* types */
13 typedef pthread_t thrd_t;
14 typedef pthread_mutex_t mtx_t;
15 typedef pthread_cond_t cnd_t;
16 typedef pthread_key_t tss_t;
17 typedef pthread_once_t once_flag;
19 typedef void (*thrd_start_t)(void*);
20 typedef void (*tss_dtor_t)(void*);
23 typedef struct {
24 time_t sec;
25 long nsec;
26 } xtime;
28 enum {
29 mtx_plain,
30 mtx_recursive,
31 mtx_timed,
32 mtx_try
33 };
35 enum {
36 thrd_success,
37 thrd_busy,
38 thrd_error,
39 thrd_nomem
40 };
43 /* ---- thread management ---- */
45 static inline int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
46 {
47 /* XXX there's a third possible value returned according to the standard:
48 * thrd_nomem. but it doesn't seem to correspond to any pthread_create errors.
49 */
50 return pthread_create(thr, 0, (void*(*)(void*))func, arg) == 0 ? thrd_success : thrd_error;
51 }
53 static inline void thrd_exit(int res)
54 {
55 pthread_exit((void*)(long)res);
56 }
58 static inline int thrd_join(thrd_t thr, int *res)
59 {
60 void *retval;
62 if(pthread_join(thr, &retval) != 0) {
63 return thrd_error;
64 }
65 if(res) {
66 *res = (long)retval;
67 }
68 return thrd_success;
69 }
71 static inline int thrd_detatch(thrd_t thr)
72 {
73 return pthread_detach(thr) == 0 ? thrd_success : thrd_error;
74 }
76 static inline thrd_t thrd_current(void)
77 {
78 return pthread_self();
79 }
81 static inline int thrd_equal(thrd_t a, thrd_t b)
82 {
83 return pthread_equal(a, b);
84 }
86 static inline void thrd_sleep(const xtime *xt)
87 {
88 int res;
89 struct timespec ts;
90 ts.tv_sec = (long)xt->sec;
91 ts.tv_nsec = xt->nsec;
93 do {
94 struct timespec rem;
95 res = nanosleep(&ts, &rem);
96 ts = rem;
97 } while(res == -1 && errno == EINTR);
98 }
100 static inline void thrd_yield(void)
101 {
102 sched_yield();
103 }
105 /* ---- mutexes ---- */
107 static inline int mtx_init(mtx_t *mtx, int type)
108 {
109 int res;
110 pthread_mutexattr_t attr;
112 pthread_mutexattr_init(&attr);
114 /* XXX I don't think these are exactly correct semantics */
115 if(type & mtx_try) {
116 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
117 }
118 if(type & mtx_timed) {
119 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP);
120 }
121 if(type & mtx_recursive) {
122 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
123 }
125 res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error;
126 pthread_mutexattr_destroy(&attr);
127 return res;
128 }
130 static inline void mtx_destroy(mtx_t *mtx)
131 {
132 pthread_mutex_destroy(mtx);
133 }
135 static inline int mtx_lock(mtx_t *mtx)
136 {
137 int res = pthread_mutex_lock(mtx);
138 if(res == EDEADLK) {
139 return thrd_busy;
140 }
141 return res == 0 ? thrd_success : thrd_error;
142 }
144 static inline int mtx_trylock(mtx_t *mtx)
145 {
146 int res = pthread_mutex_trylock(mtx);
147 if(res == EBUSY) {
148 return thrd_busy;
149 }
150 return res == 0 ? thrd_success : thrd_error;
151 }
153 static inline int mtx_timedlock(mtx_t *mtx, const xtime *xt)
154 {
155 int res;
156 struct timespec ts;
158 ts.tv_sec = (long)xt->sec;
159 ts.tv_nsec = xt->nsec;
161 if((res = pthread_mutex_timedlock(mtx, &ts)) == EBUSY) {
162 return thrd_busy;
163 }
164 return res == 0 ? thrd_success : thrd_error;
165 }
167 static inline int mtx_unlock(mtx_t *mtx)
168 {
169 return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;
170 }
172 /* ---- condition variables ---- */
174 static inline int cnd_init(cnd_t *cond)
175 {
176 return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error;
177 }
179 static inline void cnd_destroy(cnd_t *cond)
180 {
181 pthread_cond_destroy(cond);
182 }
184 static inline int cnd_signal(cnd_t *cond)
185 {
186 return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
187 }
189 static inline int cnd_broadcast(cnd_t *cond)
190 {
191 return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error;
192 }
194 static inline int cnd_wait(cnd_t *cond, mtx_t *mtx)
195 {
196 return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
197 }
199 static inline int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
200 {
201 int res;
202 struct timespec ts;
204 ts.tv_sec = (long)xt->sec;
205 ts.tv_nsec = xt->nsec;
207 if((res = pthread_cond_timedwait(cond, mtx, &ts)) != 0) {
208 return res == ETIMEDOUT ? thrd_busy : thrd_error;
209 }
210 return thrd_success;
211 }
213 /* ---- thread-specific data ---- */
215 static inline int tss_create(tss_t *key, tss_dtor_t dtor)
216 {
217 return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error;
218 }
220 static inline void tss_delete(tss_t key)
221 {
222 pthread_key_delete(key);
223 }
225 static inline int tss_set(tss_t key, void *val)
226 {
227 return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error;
228 }
230 static inline void *tss_get(tss_t key)
231 {
232 return pthread_getspecific(key);
233 }
235 /* ---- misc ---- */
237 static inline void call_once(once_flag *flag, void (*func)(void))
238 {
239 pthread_once(flag, func);
240 }
242 /* TODO take base into account */
243 static inline int xtime_get(xtime *xt, int base)
244 {
245 struct timeval tv;
247 gettimeofday(&tv, 0);
249 xt->sec = tv.tv_sec;
250 xt->nsec = tv.tv_usec * 1000;
251 return base;
252 }
254 #endif /* C11THREADS_H_ */