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 +}