diff --git a/headers/posix/pthread.h b/headers/posix/pthread.h index bf8edd1fc5..432a44fde1 100644 --- a/headers/posix/pthread.h +++ b/headers/posix/pthread.h @@ -80,8 +80,7 @@ extern "C" { extern pthread_mutex_t _pthread_mutex_static_initializer(void); extern pthread_mutex_t _pthread_recursive_mutex_static_initializer(void); -#define PTHREAD_MUTEX_INITIALIZER \ - pthread_mutex_static_initializer(); +#define PTHREAD_MUTEX_INITIALIZER NULL #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER \ pthread_recursive_mutex_static_initializer(); diff --git a/src/system/libroot/posix/pthread/pthread.c b/src/system/libroot/posix/pthread/pthread.c index cc499e47e1..a40824512f 100644 --- a/src/system/libroot/posix/pthread/pthread.c +++ b/src/system/libroot/posix/pthread/pthread.c @@ -5,6 +5,7 @@ #include #include +#include #include "pthread_private.h" static const pthread_attr pthread_attr_default = { @@ -12,6 +13,23 @@ static const pthread_attr pthread_attr_default = { B_NORMAL_PRIORITY }; +struct pthread_data { + thread_entry entry; + void *data; +}; + +static int32 +_pthread_thread_entry(void *entry_data) +{ + struct pthread_data *pdata = (struct pthread_data *)entry_data; + thread_func entry = pdata->entry; + void *data = pdata->data; + + free(pdata); + on_exit_thread(_pthread_key_call_destructors, NULL); + return entry(data); +} + int pthread_create(pthread_t *_thread, const pthread_attr_t *_attr, @@ -19,6 +37,7 @@ pthread_create(pthread_t *_thread, const pthread_attr_t *_attr, { thread_id thread; const pthread_attr *attr = NULL; + struct pthread_data *pdata; if (_thread == NULL) return B_BAD_VALUE; @@ -28,7 +47,13 @@ pthread_create(pthread_t *_thread, const pthread_attr_t *_attr, else attr = *_attr; - thread = spawn_thread((thread_entry)start_routine, "pthread func", attr->sched_priority, arg); + pdata = malloc(sizeof(struct pthread_data)); + if (!pdata) + return B_WOULD_BLOCK; + pdata->entry = (thread_entry)start_routine; + pdata->data = arg; + + thread = spawn_thread(_pthread_thread_entry, "pthread func", attr->sched_priority, pdata); if (thread < B_OK) return B_WOULD_BLOCK; // stupid error code (EAGAIN) but demanded by POSIX @@ -56,10 +81,9 @@ pthread_equal(pthread_t t1, pthread_t t2) int pthread_join(pthread_t thread, void **value_ptr) { - status_t err = wait_for_thread(thread, (status_t *)value_ptr); - if (err == B_BAD_THREAD_ID) - return ESRCH; - return err; + wait_for_thread(thread, (status_t *)value_ptr); + /* the thread could be joinable and gone */ + return B_OK; } diff --git a/src/system/libroot/posix/pthread/pthread_key.c b/src/system/libroot/posix/pthread/pthread_key.c index 010fbc901a..7cacc4fb53 100644 --- a/src/system/libroot/posix/pthread/pthread_key.c +++ b/src/system/libroot/posix/pthread/pthread_key.c @@ -6,25 +6,85 @@ #include #include +#include #include "pthread_private.h" +struct key_link { + struct key_link *next; + pthread_key_t key; + void (*destructor)(void*); +}; + +static pthread_mutex_t sKeyLock = PTHREAD_MUTEX_INITIALIZER; +static struct key_link *sKeyList = NULL; + + +void +_pthread_key_call_destructors(void *param) +{ + struct key_link *link = NULL; + + pthread_mutex_lock(&sKeyLock); + + for (link = sKeyList; link; link = link->next) { + void *data = pthread_getspecific(link->key); + if (link->destructor && data) + (*link->destructor)(data); + } + + pthread_mutex_unlock(&sKeyLock); +} + + int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) { + struct key_link *link; + if (key == NULL) return B_BAD_VALUE; + pthread_mutex_lock(&sKeyLock); *key = tls_allocate(); - if (*key > 0) - return B_OK; - return *key; + if (*key < 0) { + pthread_mutex_unlock(&sKeyLock); + return *key; + } + + // add key/destructor to the list + link = malloc(sizeof(struct key_link)); + if (!link) + return B_WOULD_BLOCK; + link->next = sKeyList; + link->key = *key; + link->destructor= destructor; + sKeyList = link; + pthread_mutex_unlock(&sKeyLock); + return B_OK; } int pthread_key_delete(pthread_key_t key) { - // we don't check if the key is valid - return B_OK; + struct key_link *link, *last = NULL; + pthread_mutex_lock(&sKeyLock); + + //remove key/destructor from the list + for (link = sKeyList; link; link = link->next) { + if (link->key == key) { + if (last) + last->next = link->next; + else + sKeyList = link->next; + free(link); + pthread_mutex_unlock(&sKeyLock); + return B_OK; + } + last = link; + } + + pthread_mutex_unlock(&sKeyLock); + return B_BAD_VALUE; } diff --git a/src/system/libroot/posix/pthread/pthread_mutex.c b/src/system/libroot/posix/pthread/pthread_mutex.c index 2bc4391984..044b2034c9 100644 --- a/src/system/libroot/posix/pthread/pthread_mutex.c +++ b/src/system/libroot/posix/pthread/pthread_mutex.c @@ -166,6 +166,9 @@ pthread_mutex_lock(pthread_mutex_t *_mutex) if (_mutex == NULL) return B_BAD_VALUE; + if (*_mutex == NULL) + pthread_mutex_init(_mutex, NULL); + return mutex_lock(*_mutex, B_INFINITE_TIMEOUT); } diff --git a/src/system/libroot/posix/pthread/pthread_private.h b/src/system/libroot/posix/pthread/pthread_private.h index 3eafaf472b..4a45b11916 100644 --- a/src/system/libroot/posix/pthread/pthread_private.h +++ b/src/system/libroot/posix/pthread/pthread_private.h @@ -30,4 +30,7 @@ typedef struct _pthread_attr { int32 sched_priority; } pthread_attr; + +void _pthread_key_call_destructors(void *); + #endif /* _PTHREAD_PRIVATE_H_ */