summaryrefslogtreecommitdiff
path: root/src/thread-pthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/thread-pthread.c')
-rw-r--r--src/thread-pthread.c344
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));
+}