diff options
Diffstat (limited to 'nptl/pthread_join.c')
-rw-r--r-- | nptl/pthread_join.c | 80 |
1 files changed, 37 insertions, 43 deletions
diff --git a/nptl/pthread_join.c b/nptl/pthread_join.c index c88d85b52f..f94128dd96 100644 --- a/nptl/pthread_join.c +++ b/nptl/pthread_join.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -20,18 +20,14 @@ #include <errno.h> #include <stdlib.h> -#include <atomic.h> +#include "atomic.h" #include "pthreadP.h" static void cleanup (void *arg) { - /* If we already changed the waiter ID, reset it. The call cannot - fail for any reason but the thread not having done that yet so - there is no reason for a loop. */ - atomic_compare_and_exchange_bool_acq ((struct pthread **) arg, NULL, - THREAD_SELF); + *(void **) arg = NULL; } @@ -40,6 +36,7 @@ pthread_join (threadid, thread_return) pthread_t threadid; void **thread_return; { + struct pthread *self; struct pthread *pd = (struct pthread *) threadid; /* Make sure the descriptor is valid. */ @@ -52,23 +49,12 @@ pthread_join (threadid, thread_return) /* We cannot wait for the thread. */ return EINVAL; - struct pthread *self = THREAD_SELF; - int result = 0; - - /* During the wait we change to asynchronous cancellation. If we - are canceled the thread we are waiting for must be marked as - un-wait-ed for again. */ - pthread_cleanup_push (cleanup, &pd->joinid); - - /* Switch to asynchronous cancellation. */ - int oldtype = CANCEL_ASYNC (); - - if ((pd == self - || (self->joinid == pd - && (pd->cancelhandling - & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK - | TERMINATED_BITMASK)) == 0)) - && !CANCEL_ENABLED_AND_CANCELED (self->cancelhandling)) + self = THREAD_SELF; + if (pd == self + || (self->joinid == pd + && (pd->cancelhandling + & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK + | TERMINATED_BITMASK)) == 0)) /* This is a deadlock situation. The threads are waiting for each other to finish. Note that this is a "may" error. To be 100% sure we catch this error we would have to lock the data @@ -76,17 +62,28 @@ pthread_join (threadid, thread_return) two threads are really caught in this situation they will deadlock. It is the programmer's problem to figure this out. */ - result = EDEADLK; + return EDEADLK; + /* Wait for the thread to finish. If it is already locked something is wrong. There can only be one waiter. */ - else if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid, - self, - NULL), 0)) + if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid, + self, + NULL), 0)) /* There is already somebody waiting for the thread. */ - result = EINVAL; - else - /* Wait for the child. */ - lll_wait_tid (pd->tid); + return EINVAL; + + + /* During the wait we change to asynchronous cancellation. If we + are cancelled the thread we are waiting for must be marked as + un-wait-ed for again. */ + pthread_cleanup_push (cleanup, &pd->joinid); + + /* Switch to asynchronous cancellation. */ + int oldtype = CANCEL_ASYNC (); + + + /* Wait for the child. */ + lll_wait_tid (pd->tid); /* Restore cancellation mode. */ @@ -96,19 +93,16 @@ pthread_join (threadid, thread_return) pthread_cleanup_pop (0); - if (__builtin_expect (result == 0, 1)) - { - /* We mark the thread as terminated and as joined. */ - pd->tid = -1; + /* We mark the thread as terminated and as joined. */ + pd->tid = -1; - /* Store the return value if the caller is interested. */ - if (thread_return != NULL) - *thread_return = pd->result; + /* Store the return value if the caller is interested. */ + if (thread_return != NULL) + *thread_return = pd->result; - /* Free the TCB. */ - __free_tcb (pd); - } + /* Free the TCB. */ + __free_tcb (pd); - return result; + return 0; } |