c11threads

annotate c11threads.h @ 0:056c9db89e79

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 24 Sep 2012 12:32:42 +0300
parents
children
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_ */