diff options
author | davidxu <davidxu@FreeBSD.org> | 2005-04-02 01:20:00 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2005-04-02 01:20:00 +0000 |
commit | f066519e91e2290cb79ef12fe7c958ee462cda6c (patch) | |
tree | 6aaef5f553a6539306bd6f5679d039ed3c2abcce /lib/libthr/thread/thr_join.c | |
parent | 3cc412b7837a105c757df856c422eb5f497bad67 (diff) | |
download | FreeBSD-src-f066519e91e2290cb79ef12fe7c958ee462cda6c.zip FreeBSD-src-f066519e91e2290cb79ef12fe7c958ee462cda6c.tar.gz |
Import my recent 1:1 threading working. some features improved includes:
1. fast simple type mutex.
2. __thread tls works.
3. asynchronous cancellation works ( using signal ).
4. thread synchronization is fully based on umtx, mainly, condition
variable and other synchronization objects were rewritten by using
umtx directly. those objects can be shared between processes via
shared memory, it has to change ABI which does not happen yet.
5. default stack size is increased to 1M on 32 bits platform, 2M for
64 bits platform.
As the result, some mysql super-smack benchmarks show performance is
improved massivly.
Okayed by: jeff, mtm, rwatson, scottl
Diffstat (limited to 'lib/libthr/thread/thr_join.c')
-rw-r--r-- | lib/libthr/thread/thr_join.c | 187 |
1 files changed, 46 insertions, 141 deletions
diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c index 29dd421..c44b261 100644 --- a/lib/libthr/thread/thr_join.c +++ b/lib/libthr/thread/thr_join.c @@ -31,170 +31,75 @@ * * $FreeBSD$ */ + #include <errno.h> #include <pthread.h> -#include <stdlib.h> + #include "thr_private.h" __weak_reference(_pthread_join, pthread_join); +static void backout_join(void *arg) +{ + struct pthread *curthread = _get_curthread(); + struct pthread *pthread = (struct pthread *)arg; + + THREAD_LIST_LOCK(curthread); + pthread->joiner = NULL; + THREAD_LIST_UNLOCK(curthread); +} + int _pthread_join(pthread_t pthread, void **thread_return) { - int ret, dead; - pthread_t thread; + struct pthread *curthread = _get_curthread(); + void *tmp; + long state; + int oldcancel; + int ret = 0; - /* Check if the caller has specified an invalid thread: */ - if (pthread->magic != PTHREAD_MAGIC) - /* Invalid thread: */ - return(EINVAL); + if (pthread == NULL) + return (EINVAL); - /* Check if the caller has specified itself: */ if (pthread == curthread) - /* Avoid a deadlock condition: */ - return(EDEADLK); + return (EDEADLK); - /* - * Search for the specified thread in the list of active threads. This - * is done manually here rather than calling _find_thread() because - * the searches in _thread_list and _dead_list (as well as setting up - * join/detach state) have to be done atomically. - */ - ret = 0; - dead = 0; - thread = NULL; - _thread_sigblock(); - DEAD_LIST_LOCK; - THREAD_LIST_LOCK; - if (!pthread->isdead) { - TAILQ_FOREACH(thread, &_thread_list, tle) { - if (thread == pthread) { - PTHREAD_LOCK(pthread); - break; - } - } - } - if (thread == NULL) { - TAILQ_FOREACH(thread, &_dead_list, dle) { - if (thread == pthread) { - PTHREAD_LOCK(pthread); - dead = 1; - break; - } - } - } - - /* Check if the thread was not found or has been detached: */ - if (thread == NULL) { - THREAD_LIST_UNLOCK; - DEAD_LIST_UNLOCK; - _thread_sigunblock(); + THREAD_LIST_LOCK(curthread); + if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) { ret = ESRCH; - goto out; - } - if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { - PTHREAD_UNLOCK(pthread); - THREAD_LIST_UNLOCK; - DEAD_LIST_UNLOCK; - _thread_sigunblock(); - ret = EINVAL; - goto out; - } - - if (pthread->joiner != NULL) { + } else if ((pthread->tlflags & TLFLAGS_DETACHED) != 0) { + ret = ESRCH; + } else if (pthread->joiner != NULL) { /* Multiple joiners are not supported. */ - /* XXXTHR - support multiple joiners. */ - PTHREAD_UNLOCK(pthread); - THREAD_LIST_UNLOCK; - DEAD_LIST_UNLOCK; - _thread_sigunblock(); ret = ENOTSUP; - goto out; - } + if (ret) { + THREAD_LIST_UNLOCK(curthread); + return (ret); + } + /* Set the running thread to be the joiner: */ + pthread->joiner = curthread; - /* Check if the thread is not dead: */ - if (!dead) { - /* Set the running thread to be the joiner: */ - pthread->joiner = curthread; - PTHREAD_UNLOCK(pthread); - - /* Keep track of which thread we're joining to: */ - curthread->join_status.thread = pthread; - - while (curthread->join_status.thread == pthread) { - /* Wait for our signal to wake up. */ - THREAD_LIST_UNLOCK; - DEAD_LIST_UNLOCK; - _thread_sigunblock(); - if (curthread->cancellation != CS_NULL) - pthread->joiner = NULL; - _thread_enter_cancellation_point(); - - /* - * XXX - Workaround to make a join a cancellation - * point. Must find a better solution. - */ - PTHREAD_LOCK(curthread); - curthread->flags |= PTHREAD_FLAGS_SUSPENDED; - PTHREAD_UNLOCK(curthread); - ret = _thread_suspend(curthread, NULL); - if (ret != 0 && ret != EAGAIN && ret != EINTR) - PANIC("Unable to suspend in join."); - PTHREAD_LOCK(curthread); - curthread->flags &= ~PTHREAD_FLAGS_SUSPENDED; - PTHREAD_UNLOCK(curthread); - if (curthread->cancellation != CS_NULL) - pthread->joiner = NULL; - _thread_leave_cancellation_point(); + THREAD_LIST_UNLOCK(curthread); - /* - * XXX - For correctness reasons. - * We must aquire these in the same order and also - * importantly, release in the same order because - * otherwise we might deadlock with the joined thread - * when we attempt to release one of these locks. - */ - _thread_sigblock(); - DEAD_LIST_LOCK; - THREAD_LIST_LOCK; - } + THR_CLEANUP_PUSH(curthread, backout_join, pthread); + oldcancel = _thr_cancel_enter(curthread); - /* - * The thread return value and error are set by the thread we're - * joining to when it exits or detaches: - */ - ret = curthread->join_status.error; - if ((ret == 0) && (thread_return != NULL)) - *thread_return = curthread->join_status.ret; - THREAD_LIST_UNLOCK; - DEAD_LIST_UNLOCK; - _thread_sigunblock(); - } else { - /* - * The thread exited (is dead) without being detached, and no - * thread has joined it. - */ + while ((state = pthread->state) != PS_DEAD) { + _thr_umtx_wait(&pthread->state, state, NULL); + } - /* Check if the return value is required: */ - if (thread_return != NULL) { - /* Return the thread's return value: */ - *thread_return = pthread->ret; - } + _thr_cancel_leave(curthread, oldcancel); + THR_CLEANUP_POP(curthread, 0); - /* Free all remaining memory allocated to the thread. */ - pthread->attr.flags |= PTHREAD_DETACHED; - PTHREAD_UNLOCK(pthread); - TAILQ_REMOVE(&_dead_list, pthread, dle); - deadlist_free_onethread(pthread); - THREAD_LIST_UNLOCK; - DEAD_LIST_UNLOCK; - _thread_sigunblock(); - } + tmp = pthread->ret; + THREAD_LIST_LOCK(curthread); + pthread->tlflags |= TLFLAGS_DETACHED; + THR_GCLIST_ADD(pthread); + THREAD_LIST_UNLOCK(curthread); -out: - _thread_leave_cancellation_point(); + if (thread_return != NULL) + *thread_return = tmp; - /* Return the completion status: */ return (ret); } |