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