From 7d83e5c7816b5e343695a75ba58b32dbe1be969a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 1 Oct 2007 20:16:28 +0000 Subject: move all sources down to a seperate src/ tree git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@34 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- src/thread.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 src/thread.c (limited to 'src/thread.c') diff --git a/src/thread.c b/src/thread.c new file mode 100644 index 0000000..26deccb --- /dev/null +++ b/src/thread.c @@ -0,0 +1,214 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "thread.h" +#include "malloc.h" +#include "once.h" +#include "macro.h" + +struct sa_thread { + pthread_t id; + sa_thread_func_t thread_func; + void *userdata; + int running; + pthread_mutex_t running_mutex; +}; + +struct sa_tls { + pthread_key_t key; +}; + +static sa_tls_t *thread_tls; +static sa_once_t thread_tls_once = SA_ONCE_INIT; + +static void tls_free_cb(void *p) { + sa_thread_t *t = p; + + sa_assert(t); + + if (!t->thread_func) + /* This is a foreign thread, we need to free the struct */ + sa_free(t); +} + +static void thread_tls_once_func(void) { + thread_tls = sa_tls_new(tls_free_cb); +} + +static void* internal_thread_func(void *userdata) { + sa_thread_t *t = userdata; + sa_assert(t); + + t->id = pthread_self(); + sa_tls_set(thread_tls, t); + + t->thread_func(t->userdata); + + sa_assert_success(pthread_mutex_lock(&t->running_mutex)); + t->running = 0; + sa_assert_success(pthread_mutex_unlock(&t->running_mutex)); + + return NULL; +} + +sa_thread_t* sa_thread_new(sa_thread_func_t thread_func, void *userdata) { + sa_thread_t *t; + + sa_assert(thread_func); + + if (sa_once(&thread_tls_once, thread_tls_once_func) < 0 || !thread_tls) + return NULL; + + if (!(t = sa_new(sa_thread_t, 1))) + return NULL; + + t->thread_func = thread_func; + t->userdata = userdata; + + sa_assert_success(pthread_mutex_init(&t->running_mutex, NULL)); + t->running = 1; + + if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) { + sa_assert_success(pthread_mutex_destroy(&t->running_mutex)); + sa_free(t); + return NULL; + } + + return t; +} + +int sa_thread_is_running(sa_thread_t *t) { + int b; + sa_assert(t); + + if (!t->thread_func) { + /* Mhmm, this is a foreign thread, t->running is not + * necessarily valid. We misuse pthread_getschedparam() to + * check if the thread is valid. This might not be portable. */ + + int policy; + struct sched_param param; + + return pthread_getschedparam(t->id, &policy, ¶m) >= 0 || errno != ESRCH; + } + + sa_assert_success(pthread_mutex_lock(&t->running_mutex)); + b = t->running; + sa_assert_success(pthread_mutex_unlock(&t->running_mutex)); + + return !!b; +} + +void sa_thread_free(sa_thread_t *t) { + sa_assert(t); + + sa_thread_join(t); + sa_assert_success(pthread_mutex_destroy(&t->running_mutex)); + sa_free(t); +} + +int sa_thread_join(sa_thread_t *t) { + sa_assert(t); + + return pthread_join(t->id, NULL); +} + +sa_thread_t* sa_thread_self(void) { + sa_thread_t *t; + + if (sa_once(&thread_tls_once, thread_tls_once_func) < 0 || !thread_tls) + return NULL; + + if ((t = sa_tls_get(thread_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_t, 1))) + return NULL; + + t->id = pthread_self(); + t->thread_func = NULL; + t->userdata = NULL; + t->running = 1; + + sa_tls_set(thread_tls, t); + + return t; +} + +int sa_thread_is_self(sa_thread_t *t) { + sa_thread_t *c; + sa_assert(t); + + if (sa_once(&thread_tls_once, thread_tls_once_func) < 0 || !thread_tls) + return 0; + + if ((c = sa_tls_get(thread_tls))) + return c == t; + + return 0; +} + + +void* sa_thread_get_data(sa_thread_t *t) { + sa_assert(t); + + return t->userdata; +} + +void sa_thread_set_data(sa_thread_t *t, void *userdata) { + sa_assert(t); + + t->userdata = userdata; +} + +void sa_thread_yield(void) { +#ifdef HAVE_PTHREAD_YIELD + pthread_yield(); +#else + sa_assert_success(sched_yield()); +#endif +} + +sa_tls_t* sa_tls_new(sa_free_func_t free_cb) { + sa_tls_t *t; + + if (!(t = sa_new(sa_tls_t, 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 *t) { + sa_assert(t); + + sa_assert_success(pthread_key_delete(t->key)); + sa_free(t); +} + +void *sa_tls_get(sa_tls_t *t) { + sa_assert(t); + + return pthread_getspecific(t->key); +} + +void *sa_tls_set(sa_tls_t *t, void *userdata) { + void *r; + + r = pthread_getspecific(t->key); + sa_assert_success(pthread_setspecific(t->key, userdata)); + return r; +} + -- cgit