diff options
Diffstat (limited to 'src/thread-pthread.c')
| -rw-r--r-- | src/thread-pthread.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/src/thread-pthread.c b/src/thread-pthread.c new file mode 100644 index 0000000..ad35d77 --- /dev/null +++ b/src/thread-pthread.c @@ -0,0 +1,344 @@ +#include "common.h" + +#include "thread.h" + +#include <errno.h> +#include <pthread.h> + +#if !HAVE_PTHREAD_YIELD +#include <sched.h> +#endif + +#if !HAVE_CLOCK_GETTIME +# include <sys/time.h> +#endif + +#ifdef DEBUG +#define ABORTFAIL(x) \ + do { \ + if ((x)) abort(); \ + } while (false) +#else +#define ABORTFAIL(x) (x) +#endif + +bool thread_new(thread_run_t run, void* userdata) +{ + pthread_t thread; + pthread_attr_t attr; + assert(run); + if (pthread_attr_init(&attr)) + { + return NULL; + } + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) + { + pthread_attr_destroy(&attr); + return NULL; + } + if (pthread_create(&thread, &attr, run, userdata)) + { + pthread_attr_destroy(&attr); + return false; + } + pthread_attr_destroy(&attr); + return true; +} + +struct thread_t +{ + pthread_t thread; +}; + +thread_t* thread_joinable_new(thread_run_t run, void* userdata) +{ + thread_t* ret = malloc(sizeof(thread_t)); + pthread_attr_t attr; + assert(run); + if (!ret) + { + return NULL; + } + if (pthread_attr_init(&attr)) + { + free(ret); + return NULL; + } + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)) + { + pthread_attr_destroy(&attr); + free(ret); + return NULL; + } + if (pthread_create(&ret->thread, &attr, run, userdata)) + { + pthread_attr_destroy(&attr); + free(ret); + return NULL; + } + pthread_attr_destroy(&attr); + return ret; +} + +void* thread_join(thread_t* thread) +{ + void* ret; + assert(thread); + ABORTFAIL(pthread_join(thread->thread, &ret)); + free(thread); + return ret; +} + +struct thread_id_t +{ + pthread_t thread; +}; + +thread_id_t* thread_id_new(thread_t* thread) +{ + thread_id_t* id = malloc(sizeof(thread_id_t)); + if (id) + { + id->thread = thread ? thread->thread : pthread_self(); + } + return id; +} + +void thread_id_free(thread_id_t* id) +{ + free(id); +} + +bool thread_id_is_current(thread_id_t* id) +{ + assert(id); + return id->thread == pthread_self(); +} + +void thread_yield(void) +{ +#if HAVE_PTHREAD_YIELD +# if PTHREAD_YIELD_VOID + pthread_yield(); +# else + ABORTFAIL(pthread_yield()); +# endif +#else + ABORTFAIL(sched_yield()); +#endif +} + +struct thread_lock_t +{ + pthread_mutex_t mutex; +}; + +thread_lock_t* thread_lock_new(void) +{ + thread_lock_t* lock = malloc(sizeof(thread_lock_t)); + if (!lock) + { + return lock; + } + for (;;) + { +#ifdef DEBUG + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr)) + { + break; + } + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + if (pthread_mutex_init(&lock->mutex, &attr)) + { + pthread_mutexattr_destroy(&attr); + break; + } + pthread_mutexattr_destroy(&attr); +#else + if (pthread_mutex_init(&lock->mutex, NULL)) + { + break; + } +#endif + return lock; + } + free(lock); + return NULL; +} + +thread_lock_t* thread_lock_recursive_new(void) +{ + thread_lock_t* lock = malloc(sizeof(thread_lock_t)); + for (;;) + { + if (!lock) + { + break; + } + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr)) + { + break; + } + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + if (pthread_mutex_init(&lock->mutex, &attr)) + { + pthread_mutexattr_destroy(&attr); + break; + } + pthread_mutexattr_destroy(&attr); + return lock; + } + free(lock); + return NULL; +} + +void thread_lock_free(thread_lock_t* lock) +{ + if (lock) + { + pthread_mutex_destroy(&lock->mutex); + free(lock); + } +} + +void thread_lock_lock(thread_lock_t* lock) +{ + assert(lock); + ABORTFAIL(pthread_mutex_lock(&lock->mutex)); +} + +void thread_lock_unlock(thread_lock_t* lock) +{ + assert(lock); + ABORTFAIL(pthread_mutex_unlock(&lock->mutex)); +} + +struct thread_cond_t +{ + pthread_cond_t cond; +}; + +thread_cond_t* thread_cond_new(void) +{ + thread_cond_t* cond = malloc(sizeof(thread_cond_t)); + if (cond) + { + if (pthread_cond_init(&cond->cond, NULL)) + { + free(cond); + return NULL; + } + } + return cond; +} + +void thread_cond_free(thread_cond_t* cond) +{ + if (cond) + { + pthread_cond_destroy(&cond->cond); + free(cond); + } +} + +void thread_cond_wait(thread_cond_t* cond, thread_lock_t* lock) +{ + assert(cond); + assert(lock); + ABORTFAIL(pthread_cond_wait(&cond->cond, &lock->mutex)); +} + +bool thread_cond_timedwait(thread_cond_t* cond, thread_lock_t* lock, + const struct timespec *abstime) +{ + int ret; + assert(cond); + assert(lock); + assert(abstime); + ret = pthread_cond_timedwait(&cond->cond, &lock->mutex, abstime); + if (ret == 0) + { + return true; + } +#ifdef DEBUG + if (ret != ETIMEDOUT) + { + abort(); + } +#endif + return false; +} + +void thread_cond_signal(thread_cond_t* cond) +{ + assert(cond); + ABORTFAIL(pthread_cond_signal(&cond->cond)); +} + +void thread_cond_broadcast(thread_cond_t* cond) +{ + ABORTFAIL(pthread_cond_broadcast(&cond->cond)); +} + +void thread_abstime(struct timespec *abstime, unsigned long add_ms) +{ +#if HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_REALTIME, abstime); +#else + { + struct timeval tv; + gettimeofday(&tv, NULL); + abstime->tv_sec = tv.tv_sec; + abstime->tv_nsec = tv.tv_usec * 1000; + } +#endif + timespec_addms(abstime, add_ms); +} + +struct thread_data_t +{ + pthread_key_t key; +}; + +thread_data_t *thread_data_new(thread_data_value_free_t free_value) +{ + thread_data_t *data = malloc(sizeof(thread_data_t)); + if (data) + { + if (pthread_key_create(&data->key, free_value)) + { + free(data); + return NULL; + } + } + return data; +} + +void thread_data_free(thread_data_t *data) +{ + if (data) + { + pthread_key_delete(data->key); + free(data); + } +} + +void *thread_data_value(thread_data_t *data) +{ + assert(data); + return pthread_getspecific(data->key); +} + +void thread_data_set(thread_data_t *data, void *value) +{ + assert(data); + ABORTFAIL(pthread_setspecific(data->key, value)); +} + +void thread_once(thread_once_t *once, thread_run_once_t run) +{ + assert(once && run); + ABORTFAIL(pthread_once(once, run)); +} |
