From 18301dfca56ba8545549e80f84423d83a46c6b64 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 2 Oct 2007 20:26:08 +0000 Subject: a lot of minor cleanups git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@36 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- src/thread-posix.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 src/thread-posix.c (limited to 'src/thread-posix.c') diff --git a/src/thread-posix.c b/src/thread-posix.c new file mode 100644 index 0000000..d76e8d5 --- /dev/null +++ b/src/thread-posix.c @@ -0,0 +1,215 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "malloc.h" +#include "mutex.h" +#include "macro.h" +#include "thread.h" + +struct sa_thread { + pthread_t id; + sa_thread_func_t thread_func; + void *userdata; + int running; + sa_mutex *mutex; +}; + +struct sa_tls { + pthread_key_t key; +}; + +static pthread_once_t tid_once = PTHREAD_ONCE_INIT; +static sa_tls *tid_tls = NULL; + +static void tid_free_cb(void *p) { + sa_thread *t = p; + + sa_assert(t); + + if (!t->thread_func) { + /* This is a foreign thread, we need to free the struct */ + sa_mutex_free(t->mutex); + sa_free(t); + } +} + +static void tid_init(void) { + tid_tls = sa_tls_new(tid_free_cb); +} + +static void* internal_thread_func(void *userdata) { + sa_thread *t = userdata; + sa_assert(t); + + t->id = pthread_self(); + sa_tls_set(tid_tls, t); + + sa_mutex_lock(t->mutex); + t->running++; + sa_mutex_unlock(t->mutex); + + t->thread_func(t->userdata); + + sa_mutex_lock(t->mutex); + t->running -= 2; + sa_mutex_unlock(t->mutex); + + return NULL; +} + +sa_thread* sa_thread_new(sa_thread_func_t thread_func, void *userdata) { + sa_thread *t; + + sa_assert(thread_func); + + pthread_once(&tid_once, tid_init); + + if (!tid_tls) + return NULL; + + if (!(t = sa_new(sa_thread, 1))) + return NULL; + + t->thread_func = thread_func; + t->userdata = userdata; + t->running = 1; + + if (!(t->mutex = sa_mutex_new(FALSE, FALSE))) { + sa_free(t); + return NULL; + } + + if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) { + sa_mutex_free(t->mutex); + sa_free(t); + return NULL; + } + + return t; +} + +sa_bool_t sa_thread_is_running(sa_thread *t) { + sa_bool_t b; + sa_assert(t); + + /* Unfortunately there is no way to tell whether a "foreign" + * thread is still running. See + * http://udrepper.livejournal.com/16844.html for more + * information */ + sa_assert(t->thread_func); + + sa_mutex_lock(t->mutex); + b = t->running > 0; + sa_mutex_unlock(t->mutex); + + return b; +} + +void sa_thread_free(sa_thread *t) { + sa_assert(t); + + /* Only allowed when this is not a foreign thread */ + sa_assert(t->thread_func); + + sa_thread_join(t); + sa_mutex_free(t->mutex); + sa_free(t); +} + +int sa_thread_join(sa_thread *t) { + sa_assert(t); + + /* Only allowed when this is not a foreign thread */ + sa_assert(t->thread_func); + + return pthread_join(t->id, NULL); +} + +sa_thread* sa_thread_self(void) { + sa_thread *t; + + pthread_once(&tid_once, tid_init); + + if (!tid_tls) + return NULL; + + if ((t = sa_tls_get(tid_tls))) + return t; + + /* This is a foreign thread, let's create a pthread structure to + * make sure that we can always return a sensible pointer */ + + if (!(t = sa_new(sa_thread, 1))) + return NULL; + + t->id = pthread_self(); + t->thread_func = NULL; + t->userdata = NULL; + t->running = 2; + t->mutex = sa_mutex_new(FALSE, FALSE); + + sa_tls_set(tid_tls, t); + + return t; +} + +void* sa_thread_get_data(sa_thread *t) { + sa_assert(t); + + return t->userdata; +} + +void sa_thread_set_data(sa_thread *t, void *userdata) { + sa_assert(t); + + t->userdata = userdata; +} + +void sa_thread_yield(void) { +#ifdef HAVE_PTHREAD_YIELD + pthread_yield(); +#else + sa_assert_se(sched_yield() == 0); +#endif +} + +sa_tls* sa_tls_new(sa_free_cb_t free_cb) { + sa_tls *t; + + if (!(t = sa_new(sa_tls, 1))) + return NULL; + + if (pthread_key_create(&t->key, free_cb) < 0) { + sa_free(t); + return NULL; + } + + return t; +} + +void sa_tls_free(sa_tls *t) { + sa_assert(t); + + sa_assert_se(pthread_key_delete(t->key) == 0); + sa_free(t); +} + +void *sa_tls_get(sa_tls *t) { + sa_assert(t); + + return pthread_getspecific(t->key); +} + +void *sa_tls_set(sa_tls *t, void *userdata) { + void *r; + + sa_assert(t); + r = pthread_getspecific(t->key); + sa_assert_se(pthread_setspecific(t->key, userdata) == 0); + return r; +} -- cgit