c11threads

diff c11threads.h @ 0:056c9db89e79

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 24 Sep 2012 12:32:42 +0300
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/c11threads.h	Mon Sep 24 12:32:42 2012 +0300
     1.3 @@ -0,0 +1,254 @@
     1.4 +#ifndef C11THREADS_H_
     1.5 +#define C11THREADS_H_
     1.6 +
     1.7 +#include <time.h>
     1.8 +#include <errno.h>
     1.9 +#include <pthread.h>
    1.10 +#include <sched.h>	/* for sched_yield */
    1.11 +#include <sys/time.h>
    1.12 +
    1.13 +#define ONCE_FLAG_INIT	PTHREAD_ONCE_INIT
    1.14 +
    1.15 +/* types */
    1.16 +typedef pthread_t thrd_t;
    1.17 +typedef pthread_mutex_t mtx_t;
    1.18 +typedef pthread_cond_t cnd_t;
    1.19 +typedef pthread_key_t tss_t;
    1.20 +typedef pthread_once_t once_flag;
    1.21 +
    1.22 +typedef void (*thrd_start_t)(void*);
    1.23 +typedef void (*tss_dtor_t)(void*);
    1.24 +
    1.25 +
    1.26 +typedef struct {
    1.27 +	time_t sec;
    1.28 +	long nsec;
    1.29 +} xtime;
    1.30 +
    1.31 +enum {
    1.32 +	mtx_plain,
    1.33 +	mtx_recursive,
    1.34 +	mtx_timed,
    1.35 +	mtx_try
    1.36 +};
    1.37 +
    1.38 +enum {
    1.39 +	thrd_success,
    1.40 +	thrd_busy,
    1.41 +	thrd_error,
    1.42 +	thrd_nomem
    1.43 +};
    1.44 +
    1.45 +
    1.46 +/* ---- thread management ---- */
    1.47 +
    1.48 +static inline int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
    1.49 +{
    1.50 +	/* XXX there's a third possible value returned according to the standard:
    1.51 +	 * thrd_nomem. but it doesn't seem to correspond to any pthread_create errors.
    1.52 +	 */
    1.53 +	return pthread_create(thr, 0, (void*(*)(void*))func, arg) == 0 ? thrd_success : thrd_error;
    1.54 +}
    1.55 +
    1.56 +static inline void thrd_exit(int res)
    1.57 +{
    1.58 +	pthread_exit((void*)(long)res);
    1.59 +}
    1.60 +
    1.61 +static inline int thrd_join(thrd_t thr, int *res)
    1.62 +{
    1.63 +	void *retval;
    1.64 +
    1.65 +	if(pthread_join(thr, &retval) != 0) {
    1.66 +		return thrd_error;
    1.67 +	}
    1.68 +	if(res) {
    1.69 +		*res = (long)retval;
    1.70 +	}
    1.71 +	return thrd_success;
    1.72 +}
    1.73 +
    1.74 +static inline int thrd_detatch(thrd_t thr)
    1.75 +{
    1.76 +	return pthread_detach(thr) == 0 ? thrd_success : thrd_error;
    1.77 +}
    1.78 +
    1.79 +static inline thrd_t thrd_current(void)
    1.80 +{
    1.81 +	return pthread_self();
    1.82 +}
    1.83 +
    1.84 +static inline int thrd_equal(thrd_t a, thrd_t b)
    1.85 +{
    1.86 +	return pthread_equal(a, b);
    1.87 +}
    1.88 +
    1.89 +static inline void thrd_sleep(const xtime *xt)
    1.90 +{
    1.91 +	int res;
    1.92 +	struct timespec ts;
    1.93 +	ts.tv_sec = (long)xt->sec;
    1.94 +	ts.tv_nsec = xt->nsec;
    1.95 +
    1.96 +	do {
    1.97 +		struct timespec rem;
    1.98 +		res = nanosleep(&ts, &rem);
    1.99 +		ts = rem;
   1.100 +	} while(res == -1 && errno == EINTR);
   1.101 +}
   1.102 +
   1.103 +static inline void thrd_yield(void)
   1.104 +{
   1.105 +	sched_yield();
   1.106 +}
   1.107 +
   1.108 +/* ---- mutexes ---- */
   1.109 +
   1.110 +static inline int mtx_init(mtx_t *mtx, int type)
   1.111 +{
   1.112 +	int res;
   1.113 +	pthread_mutexattr_t attr;
   1.114 +
   1.115 +	pthread_mutexattr_init(&attr);
   1.116 +
   1.117 +	/* XXX I don't think these are exactly correct semantics */
   1.118 +	if(type & mtx_try) {
   1.119 +		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
   1.120 +	}
   1.121 +	if(type & mtx_timed) {
   1.122 +		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP);
   1.123 +	}
   1.124 +	if(type & mtx_recursive) {
   1.125 +		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
   1.126 +	}
   1.127 +
   1.128 +	res = pthread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error;
   1.129 +	pthread_mutexattr_destroy(&attr);
   1.130 +	return res;
   1.131 +}
   1.132 +
   1.133 +static inline void mtx_destroy(mtx_t *mtx)
   1.134 +{
   1.135 +	pthread_mutex_destroy(mtx);
   1.136 +}
   1.137 +
   1.138 +static inline int mtx_lock(mtx_t *mtx)
   1.139 +{
   1.140 +	int res = pthread_mutex_lock(mtx);
   1.141 +	if(res == EDEADLK) {
   1.142 +		return thrd_busy;
   1.143 +	}
   1.144 +	return res == 0 ? thrd_success : thrd_error;
   1.145 +}
   1.146 +
   1.147 +static inline int mtx_trylock(mtx_t *mtx)
   1.148 +{
   1.149 +	int res = pthread_mutex_trylock(mtx);
   1.150 +	if(res == EBUSY) {
   1.151 +		return thrd_busy;
   1.152 +	}
   1.153 +	return res == 0 ? thrd_success : thrd_error;
   1.154 +}
   1.155 +
   1.156 +static inline int mtx_timedlock(mtx_t *mtx, const xtime *xt)
   1.157 +{
   1.158 +	int res;
   1.159 +	struct timespec ts;
   1.160 +
   1.161 +	ts.tv_sec = (long)xt->sec;
   1.162 +	ts.tv_nsec = xt->nsec;
   1.163 +
   1.164 +	if((res = pthread_mutex_timedlock(mtx, &ts)) == EBUSY) {
   1.165 +		return thrd_busy;
   1.166 +	}
   1.167 +	return res == 0 ? thrd_success : thrd_error;
   1.168 +}
   1.169 +
   1.170 +static inline int mtx_unlock(mtx_t *mtx)
   1.171 +{
   1.172 +	return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;
   1.173 +}
   1.174 +
   1.175 +/* ---- condition variables ---- */
   1.176 +
   1.177 +static inline int cnd_init(cnd_t *cond)
   1.178 +{
   1.179 +	return pthread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error;
   1.180 +}
   1.181 +
   1.182 +static inline void cnd_destroy(cnd_t *cond)
   1.183 +{
   1.184 +	pthread_cond_destroy(cond);
   1.185 +}
   1.186 +
   1.187 +static inline int cnd_signal(cnd_t *cond)
   1.188 +{
   1.189 +	return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
   1.190 +}
   1.191 +
   1.192 +static inline int cnd_broadcast(cnd_t *cond)
   1.193 +{
   1.194 +	return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error;
   1.195 +}
   1.196 +
   1.197 +static inline int cnd_wait(cnd_t *cond, mtx_t *mtx)
   1.198 +{
   1.199 +	return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
   1.200 +}
   1.201 +
   1.202 +static inline int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
   1.203 +{
   1.204 +	int res;
   1.205 +	struct timespec ts;
   1.206 +
   1.207 +	ts.tv_sec = (long)xt->sec;
   1.208 +	ts.tv_nsec = xt->nsec;
   1.209 +
   1.210 +	if((res = pthread_cond_timedwait(cond, mtx, &ts)) != 0) {
   1.211 +		return res == ETIMEDOUT ? thrd_busy : thrd_error;
   1.212 +	}
   1.213 +	return thrd_success;
   1.214 +}
   1.215 +
   1.216 +/* ---- thread-specific data ---- */
   1.217 +
   1.218 +static inline int tss_create(tss_t *key, tss_dtor_t dtor)
   1.219 +{
   1.220 +	return pthread_key_create(key, dtor) == 0 ? thrd_success : thrd_error;
   1.221 +}
   1.222 +
   1.223 +static inline void tss_delete(tss_t key)
   1.224 +{
   1.225 +	pthread_key_delete(key);
   1.226 +}
   1.227 +
   1.228 +static inline int tss_set(tss_t key, void *val)
   1.229 +{
   1.230 +	return pthread_setspecific(key, val) == 0 ? thrd_success : thrd_error;
   1.231 +}
   1.232 +
   1.233 +static inline void *tss_get(tss_t key)
   1.234 +{
   1.235 +	return pthread_getspecific(key);
   1.236 +}
   1.237 +
   1.238 +/* ---- misc ---- */
   1.239 +
   1.240 +static inline void call_once(once_flag *flag, void (*func)(void))
   1.241 +{
   1.242 +	pthread_once(flag, func);
   1.243 +}
   1.244 +
   1.245 +/* TODO take base into account */
   1.246 +static inline int xtime_get(xtime *xt, int base)
   1.247 +{
   1.248 +	struct timeval tv;
   1.249 +
   1.250 +	gettimeofday(&tv, 0);
   1.251 +
   1.252 +	xt->sec = tv.tv_sec;
   1.253 +	xt->nsec = tv.tv_usec * 1000;
   1.254 +	return base;
   1.255 +}
   1.256 +
   1.257 +#endif	/* C11THREADS_H_ */