Back to index

glibc  2.9
pthread_cancel.c
Go to the documentation of this file.
00001 /* Copyright (C) 2002, 2003, 2004 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 <signal.h>
00022 #include "pthreadP.h"
00023 #include "atomic.h"
00024 #include <sysdep.h>
00025 #include <kernel-features.h>
00026 
00027 
00028 int
00029 pthread_cancel (th)
00030      pthread_t th;
00031 {
00032   volatile struct pthread *pd = (volatile struct pthread *) th;
00033 
00034   /* Make sure the descriptor is valid.  */
00035   if (INVALID_TD_P (pd))
00036     /* Not a valid thread handle.  */
00037     return ESRCH;
00038 
00039 #ifdef SHARED
00040   pthread_cancel_init ();
00041 #endif
00042   int result = 0;
00043   int oldval;
00044   int newval;
00045   do
00046     {
00047       oldval = pd->cancelhandling;
00048       newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
00049 
00050       /* Avoid doing unnecessary work.  The atomic operation can
00051         potentially be expensive if the bug has to be locked and
00052         remote cache lines have to be invalidated.  */
00053       if (oldval == newval)
00054        break;
00055 
00056       /* If the cancellation is handled asynchronously just send a
00057         signal.  We avoid this if possible since it's more
00058         expensive.  */
00059       if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
00060        {
00061          /* Mark the cancellation as "in progress".  */
00062          atomic_bit_set (&pd->cancelhandling, CANCELING_BIT);
00063 
00064          /* The cancellation handler will take care of marking the
00065             thread as canceled.  */
00066          INTERNAL_SYSCALL_DECL (err);
00067 
00068          /* One comment: The PID field in the TCB can temporarily be
00069             changed (in fork).  But this must not affect this code
00070             here.  Since this function would have to be called while
00071             the thread is executing fork, it would have to happen in
00072             a signal handler.  But this is no allowed, pthread_cancel
00073             is not guaranteed to be async-safe.  */
00074          int val;
00075 #if __ASSUME_TGKILL
00076          val = INTERNAL_SYSCALL (tgkill, err, 3,
00077                               THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
00078                               SIGCANCEL);
00079 #else
00080 # ifdef __NR_tgkill
00081          val = INTERNAL_SYSCALL (tgkill, err, 3,
00082                               THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
00083                               SIGCANCEL);
00084          if (INTERNAL_SYSCALL_ERROR_P (val, err)
00085              && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
00086 # endif
00087            val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCANCEL);
00088 #endif
00089 
00090          if (INTERNAL_SYSCALL_ERROR_P (val, err))
00091            result = INTERNAL_SYSCALL_ERRNO (val, err);
00092 
00093          break;
00094        }
00095     }
00096   /* Mark the thread as canceled.  This has to be done
00097      atomically since other bits could be modified as well.  */
00098   while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval,
00099                                           oldval));
00100 
00101   return result;
00102 }
00103 
00104 PTHREAD_STATIC_FN_REQUIRE (pthread_create)