Back to index

glibc  2.9
pthread_join.c
Go to the documentation of this file.
00001 /* Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <stdlib.h>
00022 
00023 #include <atomic.h>
00024 #include "pthreadP.h"
00025 
00026 
00027 static void
00028 cleanup (void *arg)
00029 {
00030   /* If we already changed the waiter ID, reset it.  The call cannot
00031      fail for any reason but the thread not having done that yet so
00032      there is no reason for a loop.  */
00033   (void) atomic_compare_and_exchange_bool_acq ((struct pthread **) arg, NULL,
00034                                           THREAD_SELF);
00035 }
00036 
00037 
00038 int
00039 pthread_join (threadid, thread_return)
00040      pthread_t threadid;
00041      void **thread_return;
00042 {
00043   struct pthread *pd = (struct pthread *) threadid;
00044 
00045   /* Make sure the descriptor is valid.  */
00046   if (INVALID_NOT_TERMINATED_TD_P (pd))
00047     /* Not a valid thread handle.  */
00048     return ESRCH;
00049 
00050   /* Is the thread joinable?.  */
00051   if (IS_DETACHED (pd))
00052     /* We cannot wait for the thread.  */
00053     return EINVAL;
00054 
00055   struct pthread *self = THREAD_SELF;
00056   int result = 0;
00057 
00058   /* During the wait we change to asynchronous cancellation.  If we
00059      are canceled the thread we are waiting for must be marked as
00060      un-wait-ed for again.  */
00061   pthread_cleanup_push (cleanup, &pd->joinid);
00062 
00063   /* Switch to asynchronous cancellation.  */
00064   int oldtype = CANCEL_ASYNC ();
00065 
00066   if ((pd == self
00067        || (self->joinid == pd
00068           && (pd->cancelhandling
00069               & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK
00070                 | TERMINATED_BITMASK)) == 0))
00071       && !CANCEL_ENABLED_AND_CANCELED (self->cancelhandling))
00072     /* This is a deadlock situation.  The threads are waiting for each
00073        other to finish.  Note that this is a "may" error.  To be 100%
00074        sure we catch this error we would have to lock the data
00075        structures but it is not necessary.  In the unlikely case that
00076        two threads are really caught in this situation they will
00077        deadlock.  It is the programmer's problem to figure this
00078        out.  */
00079     result = EDEADLK;
00080   /* Wait for the thread to finish.  If it is already locked something
00081      is wrong.  There can only be one waiter.  */
00082   else if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid,
00083                                                            self,
00084                                                            NULL), 0))
00085     /* There is already somebody waiting for the thread.  */
00086     result = EINVAL;
00087   else
00088     /* Wait for the child.  */
00089     lll_wait_tid (pd->tid);
00090 
00091 
00092   /* Restore cancellation mode.  */
00093   CANCEL_RESET (oldtype);
00094 
00095   /* Remove the handler.  */
00096   pthread_cleanup_pop (0);
00097 
00098 
00099   if (__builtin_expect (result == 0, 1))
00100     {
00101       /* We mark the thread as terminated and as joined.  */
00102       pd->tid = -1;
00103 
00104       /* Store the return value if the caller is interested.  */
00105       if (thread_return != NULL)
00106        *thread_return = pd->result;
00107 
00108 
00109       /* Free the TCB.  */
00110       __free_tcb (pd);
00111     }
00112 
00113   return result;
00114 }