# HG changeset patch # User John Tsiombikas # Date 1348479162 -10800 # Node ID 056c9db89e79cb64ab222aceda21a8e5b9ca9dbf initial commit diff -r 000000000000 -r 056c9db89e79 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Mon Sep 24 12:32:42 2012 +0300 @@ -0,0 +1,14 @@ +obj = test.o +bin = test + +CFLAGS = -pedantic -Wall -g +LDFLAGS = -lpthread + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +test.o: test.c c11threads.h + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r 000000000000 -r 056c9db89e79 c11threads.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c11threads.h Mon Sep 24 12:32:42 2012 +0300 @@ -0,0 +1,254 @@ +#ifndef C11THREADS_H_ +#define C11THREADS_H_ + +#include +#include +#include +#include /* for sched_yield */ +#include + +#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT + +/* types */ +typedef pthread_t thrd_t; +typedef pthread_mutex_t mtx_t; +typedef pthread_cond_t cnd_t; +typedef pthread_key_t tss_t; +typedef pthread_once_t once_flag; + +typedef void (*thrd_start_t)(void*); +typedef void (*tss_dtor_t)(void*); + + +typedef struct { + time_t sec; + long nsec; +} xtime; + +enum { + mtx_plain, + mtx_recursive, + mtx_timed, + mtx_try +}; + +enum { + thrd_success, + thrd_busy, + thrd_error, + thrd_nomem +}; + + +/* ---- thread management ---- */ + +static inline int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + /* XXX there's a third possible value returned according to the standard: + * thrd_nomem. but it doesn't seem to correspond to any pthread_create errors. + */ + return pthread_create(thr, 0, (void*(*)(void*))func, arg) == 0 ? thrd_success : thrd_error; +} + +static inline void thrd_exit(int res) +{ + pthread_exit((void*)(long)res); +} + +static inline int thrd_join(thrd_t thr, int *res) +{ + void *retval; + + if(pthread_join(thr, &retval) != 0) { + return thrd_error; + } + if(res) { + *res = (long)retval; + } + return thrd_success; +} + +static inline int thrd_detatch(thrd_t thr) +{ + return pthread_detach(thr) == 0 ? thrd_success : thrd_error; +} + +static inline thrd_t thrd_current(void) +{ + return pthread_self(); +} + +static inline int thrd_equal(thrd_t a, thrd_t b) +{ + return pthread_equal(a, b); +} + +static inline void thrd_sleep(const xtime *xt) +{ + int res; + struct timespec ts; + ts.tv_sec = (long)xt->sec; + ts.tv_nsec = xt->nsec; + + do { + struct timespec rem; + res = nanosleep(&ts, &rem); + ts = rem; + } while(res == -1 && errno == EINTR); +} + +static inline void thrd_yield(void) +{ + sched_yield(); +} + +/* ---- mutexes ---- */ + +static inline int mtx_init(mtx_t *mtx, int type) +{ + int res; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + + /* XXX I don't think these are exactly correct semantics */ + if(type & mtx_try) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + } + if(type & mtx_timed) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); + } + if(type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + + res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + pthread_mutexattr_destroy(&attr); + return res; +} + +static inline void mtx_destroy(mtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + +static inline int mtx_lock(mtx_t *mtx) +{ + int res = pthread_mutex_lock(mtx); + if(res == EDEADLK) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static inline int mtx_trylock(mtx_t *mtx) +{ + int res = pthread_mutex_trylock(mtx); + if(res == EBUSY) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static inline int mtx_timedlock(mtx_t *mtx, const xtime *xt) +{ + int res; + struct timespec ts; + + ts.tv_sec = (long)xt->sec; + ts.tv_nsec = xt->nsec; + + if((res = pthread_mutex_timedlock(mtx, &ts)) == EBUSY) { + return thrd_busy; + } + return res == 0 ? thrd_success : thrd_error; +} + +static inline int mtx_unlock(mtx_t *mtx) +{ + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +/* ---- condition variables ---- */ + +static inline int cnd_init(cnd_t *cond) +{ + return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +static inline void cnd_destroy(cnd_t *cond) +{ + pthread_cond_destroy(cond); +} + +static inline int cnd_signal(cnd_t *cond) +{ + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +} + +static inline int cnd_broadcast(cnd_t *cond) +{ + return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +static inline int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +} + +static inline int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt) +{ + int res; + struct timespec ts; + + ts.tv_sec = (long)xt->sec; + ts.tv_nsec = xt->nsec; + + if((res = pthread_cond_timedwait(cond, mtx, &ts)) != 0) { + return res == ETIMEDOUT ? thrd_busy : thrd_error; + } + return thrd_success; +} + +/* ---- thread-specific data ---- */ + +static inline int tss_create(tss_t *key, tss_dtor_t dtor) +{ + return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error; +} + +static inline void tss_delete(tss_t key) +{ + pthread_key_delete(key); +} + +static inline int tss_set(tss_t key, void *val) +{ + return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error; +} + +static inline void *tss_get(tss_t key) +{ + return pthread_getspecific(key); +} + +/* ---- misc ---- */ + +static inline void call_once(once_flag *flag, void (*func)(void)) +{ + pthread_once(flag, func); +} + +/* TODO take base into account */ +static inline int xtime_get(xtime *xt, int base) +{ + struct timeval tv; + + gettimeofday(&tv, 0); + + xt->sec = tv.tv_sec; + xt->nsec = tv.tv_usec * 1000; + return base; +} + +#endif /* C11THREADS_H_ */ diff -r 000000000000 -r 056c9db89e79 test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test.c Mon Sep 24 12:32:42 2012 +0300 @@ -0,0 +1,34 @@ +#include +#include "c11threads.h" + +void tfunc(void *arg); + +int main(void) +{ + int i; + thrd_t threads[4]; + + for(i=0; i<4; i++) { + thrd_create(threads + i, tfunc, (void*)(long)i); + } + + for(i=0; i<4; i++) { + thrd_join(threads[i], 0); + } + + return 0; +} + +void tfunc(void *arg) +{ + int num = (long)arg; + xtime dur; + + printf("hello from thread %d\n", num); + + dur.sec = 4; + dur.nsec = 0; + thrd_sleep(&dur); + + printf("thread %d done\n", num); +}