c11threads
changeset 0:056c9db89e79 tip
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 24 Sep 2012 12:32:42 +0300 |
parents | |
children | |
files | Makefile c11threads.h test.c |
diffstat | 3 files changed, 302 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/Makefile Mon Sep 24 12:32:42 2012 +0300 1.3 @@ -0,0 +1,14 @@ 1.4 +obj = test.o 1.5 +bin = test 1.6 + 1.7 +CFLAGS = -pedantic -Wall -g 1.8 +LDFLAGS = -lpthread 1.9 + 1.10 +$(bin): $(obj) 1.11 + $(CC) -o $@ $(obj) $(LDFLAGS) 1.12 + 1.13 +test.o: test.c c11threads.h 1.14 + 1.15 +.PHONY: clean 1.16 +clean: 1.17 + rm -f $(obj) $(bin)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/c11threads.h Mon Sep 24 12:32:42 2012 +0300 2.3 @@ -0,0 +1,254 @@ 2.4 +#ifndef C11THREADS_H_ 2.5 +#define C11THREADS_H_ 2.6 + 2.7 +#include <time.h> 2.8 +#include <errno.h> 2.9 +#include <pthread.h> 2.10 +#include <sched.h> /* for sched_yield */ 2.11 +#include <sys/time.h> 2.12 + 2.13 +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT 2.14 + 2.15 +/* types */ 2.16 +typedef pthread_t thrd_t; 2.17 +typedef pthread_mutex_t mtx_t; 2.18 +typedef pthread_cond_t cnd_t; 2.19 +typedef pthread_key_t tss_t; 2.20 +typedef pthread_once_t once_flag; 2.21 + 2.22 +typedef void (*thrd_start_t)(void*); 2.23 +typedef void (*tss_dtor_t)(void*); 2.24 + 2.25 + 2.26 +typedef struct { 2.27 + time_t sec; 2.28 + long nsec; 2.29 +} xtime; 2.30 + 2.31 +enum { 2.32 + mtx_plain, 2.33 + mtx_recursive, 2.34 + mtx_timed, 2.35 + mtx_try 2.36 +}; 2.37 + 2.38 +enum { 2.39 + thrd_success, 2.40 + thrd_busy, 2.41 + thrd_error, 2.42 + thrd_nomem 2.43 +}; 2.44 + 2.45 + 2.46 +/* ---- thread management ---- */ 2.47 + 2.48 +static inline int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) 2.49 +{ 2.50 + /* XXX there's a third possible value returned according to the standard: 2.51 + * thrd_nomem. but it doesn't seem to correspond to any pthread_create errors. 2.52 + */ 2.53 + return pthread_create(thr, 0, (void*(*)(void*))func, arg) == 0 ? thrd_success : thrd_error; 2.54 +} 2.55 + 2.56 +static inline void thrd_exit(int res) 2.57 +{ 2.58 + pthread_exit((void*)(long)res); 2.59 +} 2.60 + 2.61 +static inline int thrd_join(thrd_t thr, int *res) 2.62 +{ 2.63 + void *retval; 2.64 + 2.65 + if(pthread_join(thr, &retval) != 0) { 2.66 + return thrd_error; 2.67 + } 2.68 + if(res) { 2.69 + *res = (long)retval; 2.70 + } 2.71 + return thrd_success; 2.72 +} 2.73 + 2.74 +static inline int thrd_detatch(thrd_t thr) 2.75 +{ 2.76 + return pthread_detach(thr) == 0 ? thrd_success : thrd_error; 2.77 +} 2.78 + 2.79 +static inline thrd_t thrd_current(void) 2.80 +{ 2.81 + return pthread_self(); 2.82 +} 2.83 + 2.84 +static inline int thrd_equal(thrd_t a, thrd_t b) 2.85 +{ 2.86 + return pthread_equal(a, b); 2.87 +} 2.88 + 2.89 +static inline void thrd_sleep(const xtime *xt) 2.90 +{ 2.91 + int res; 2.92 + struct timespec ts; 2.93 + ts.tv_sec = (long)xt->sec; 2.94 + ts.tv_nsec = xt->nsec; 2.95 + 2.96 + do { 2.97 + struct timespec rem; 2.98 + res = nanosleep(&ts, &rem); 2.99 + ts = rem; 2.100 + } while(res == -1 && errno == EINTR); 2.101 +} 2.102 + 2.103 +static inline void thrd_yield(void) 2.104 +{ 2.105 + sched_yield(); 2.106 +} 2.107 + 2.108 +/* ---- mutexes ---- */ 2.109 + 2.110 +static inline int mtx_init(mtx_t *mtx, int type) 2.111 +{ 2.112 + int res; 2.113 + pthread_mutexattr_t attr; 2.114 + 2.115 + pthread_mutexattr_init(&attr); 2.116 + 2.117 + /* XXX I don't think these are exactly correct semantics */ 2.118 + if(type & mtx_try) { 2.119 + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); 2.120 + } 2.121 + if(type & mtx_timed) { 2.122 + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); 2.123 + } 2.124 + if(type & mtx_recursive) { 2.125 + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 2.126 + } 2.127 + 2.128 + res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; 2.129 + pthread_mutexattr_destroy(&attr); 2.130 + return res; 2.131 +} 2.132 + 2.133 +static inline void mtx_destroy(mtx_t *mtx) 2.134 +{ 2.135 + pthread_mutex_destroy(mtx); 2.136 +} 2.137 + 2.138 +static inline int mtx_lock(mtx_t *mtx) 2.139 +{ 2.140 + int res = pthread_mutex_lock(mtx); 2.141 + if(res == EDEADLK) { 2.142 + return thrd_busy; 2.143 + } 2.144 + return res == 0 ? thrd_success : thrd_error; 2.145 +} 2.146 + 2.147 +static inline int mtx_trylock(mtx_t *mtx) 2.148 +{ 2.149 + int res = pthread_mutex_trylock(mtx); 2.150 + if(res == EBUSY) { 2.151 + return thrd_busy; 2.152 + } 2.153 + return res == 0 ? thrd_success : thrd_error; 2.154 +} 2.155 + 2.156 +static inline int mtx_timedlock(mtx_t *mtx, const xtime *xt) 2.157 +{ 2.158 + int res; 2.159 + struct timespec ts; 2.160 + 2.161 + ts.tv_sec = (long)xt->sec; 2.162 + ts.tv_nsec = xt->nsec; 2.163 + 2.164 + if((res = pthread_mutex_timedlock(mtx, &ts)) == EBUSY) { 2.165 + return thrd_busy; 2.166 + } 2.167 + return res == 0 ? thrd_success : thrd_error; 2.168 +} 2.169 + 2.170 +static inline int mtx_unlock(mtx_t *mtx) 2.171 +{ 2.172 + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; 2.173 +} 2.174 + 2.175 +/* ---- condition variables ---- */ 2.176 + 2.177 +static inline int cnd_init(cnd_t *cond) 2.178 +{ 2.179 + return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; 2.180 +} 2.181 + 2.182 +static inline void cnd_destroy(cnd_t *cond) 2.183 +{ 2.184 + pthread_cond_destroy(cond); 2.185 +} 2.186 + 2.187 +static inline int cnd_signal(cnd_t *cond) 2.188 +{ 2.189 + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; 2.190 +} 2.191 + 2.192 +static inline int cnd_broadcast(cnd_t *cond) 2.193 +{ 2.194 + return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; 2.195 +} 2.196 + 2.197 +static inline int cnd_wait(cnd_t *cond, mtx_t *mtx) 2.198 +{ 2.199 + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; 2.200 +} 2.201 + 2.202 +static inline int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt) 2.203 +{ 2.204 + int res; 2.205 + struct timespec ts; 2.206 + 2.207 + ts.tv_sec = (long)xt->sec; 2.208 + ts.tv_nsec = xt->nsec; 2.209 + 2.210 + if((res = pthread_cond_timedwait(cond, mtx, &ts)) != 0) { 2.211 + return res == ETIMEDOUT ? thrd_busy : thrd_error; 2.212 + } 2.213 + return thrd_success; 2.214 +} 2.215 + 2.216 +/* ---- thread-specific data ---- */ 2.217 + 2.218 +static inline int tss_create(tss_t *key, tss_dtor_t dtor) 2.219 +{ 2.220 + return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error; 2.221 +} 2.222 + 2.223 +static inline void tss_delete(tss_t key) 2.224 +{ 2.225 + pthread_key_delete(key); 2.226 +} 2.227 + 2.228 +static inline int tss_set(tss_t key, void *val) 2.229 +{ 2.230 + return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error; 2.231 +} 2.232 + 2.233 +static inline void *tss_get(tss_t key) 2.234 +{ 2.235 + return pthread_getspecific(key); 2.236 +} 2.237 + 2.238 +/* ---- misc ---- */ 2.239 + 2.240 +static inline void call_once(once_flag *flag, void (*func)(void)) 2.241 +{ 2.242 + pthread_once(flag, func); 2.243 +} 2.244 + 2.245 +/* TODO take base into account */ 2.246 +static inline int xtime_get(xtime *xt, int base) 2.247 +{ 2.248 + struct timeval tv; 2.249 + 2.250 + gettimeofday(&tv, 0); 2.251 + 2.252 + xt->sec = tv.tv_sec; 2.253 + xt->nsec = tv.tv_usec * 1000; 2.254 + return base; 2.255 +} 2.256 + 2.257 +#endif /* C11THREADS_H_ */
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test.c Mon Sep 24 12:32:42 2012 +0300 3.3 @@ -0,0 +1,34 @@ 3.4 +#include <stdio.h> 3.5 +#include "c11threads.h" 3.6 + 3.7 +void tfunc(void *arg); 3.8 + 3.9 +int main(void) 3.10 +{ 3.11 + int i; 3.12 + thrd_t threads[4]; 3.13 + 3.14 + for(i=0; i<4; i++) { 3.15 + thrd_create(threads + i, tfunc, (void*)(long)i); 3.16 + } 3.17 + 3.18 + for(i=0; i<4; i++) { 3.19 + thrd_join(threads[i], 0); 3.20 + } 3.21 + 3.22 + return 0; 3.23 +} 3.24 + 3.25 +void tfunc(void *arg) 3.26 +{ 3.27 + int num = (long)arg; 3.28 + xtime dur; 3.29 + 3.30 + printf("hello from thread %d\n", num); 3.31 + 3.32 + dur.sec = 4; 3.33 + dur.nsec = 0; 3.34 + thrd_sleep(&dur); 3.35 + 3.36 + printf("thread %d done\n", num); 3.37 +}