Back to index

glibc  2.9
pthread_timedjoin.c
Go to the documentation of this file.
00001 /* Copyright (C) 2002, 2003, 2005 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 #include <atomic.h>
00023 #include "pthreadP.h"
00024 
00025 
00026 static void
00027 cleanup (void *arg)
00028 {
00029   *(void **) arg = NULL;
00030 }
00031 
00032 
00033 int
00034 pthread_timedjoin_np (threadid, thread_return, abstime)
00035      pthread_t threadid;
00036      void **thread_return;
00037      const struct timespec *abstime;
00038 {
00039   struct pthread *self;
00040   struct pthread *pd = (struct pthread *) threadid;
00041   int result;
00042 
00043   /* Make sure the descriptor is valid.  */
00044   if (INVALID_NOT_TERMINATED_TD_P (pd))
00045     /* Not a valid thread handle.  */
00046     return ESRCH;
00047 
00048   /* Is the thread joinable?.  */
00049   if (IS_DETACHED (pd))
00050     /* We cannot wait for the thread.  */
00051     return EINVAL;
00052 
00053   self = THREAD_SELF;
00054   if (pd == self || self->joinid == pd)
00055     /* This is a deadlock situation.  The threads are waiting for each
00056        other to finish.  Note that this is a "may" error.  To be 100%
00057        sure we catch this error we would have to lock the data
00058        structures but it is not necessary.  In the unlikely case that
00059        two threads are really caught in this situation they will
00060        deadlock.  It is the programmer's problem to figure this
00061        out.  */
00062     return EDEADLK;
00063 
00064   /* Wait for the thread to finish.  If it is already locked something
00065      is wrong.  There can only be one waiter.  */
00066   if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid,
00067                                                        self, NULL), 0))
00068     /* There is already somebody waiting for the thread.  */
00069     return EINVAL;
00070 
00071 
00072   /* During the wait we change to asynchronous cancellation.  If we
00073      are cancelled the thread we are waiting for must be marked as
00074      un-wait-ed for again.  */
00075   pthread_cleanup_push (cleanup, &pd->joinid);
00076 
00077   /* Switch to asynchronous cancellation.  */
00078   int oldtype = CANCEL_ASYNC ();
00079 
00080 
00081   /* Wait for the child.  */
00082   result = lll_timedwait_tid (pd->tid, abstime);
00083 
00084 
00085   /* Restore cancellation mode.  */
00086   CANCEL_RESET (oldtype);
00087 
00088   /* Remove the handler.  */
00089   pthread_cleanup_pop (0);
00090 
00091 
00092   /* We might have timed out.  */
00093   if (result == 0)
00094     {
00095       /* Store the return value if the caller is interested.  */
00096       if (thread_return != NULL)
00097        *thread_return = pd->result;
00098 
00099 
00100       /* Free the TCB.  */
00101       __free_tcb (pd);
00102     }
00103   else
00104     pd->joinid = NULL;
00105 
00106   return result;
00107 }