| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Copyright (C) 2002-2016 Free Software Foundation, Inc. | 
|  | 2 | This file is part of the GNU C Library. | 
|  | 3 | Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. | 
|  | 4 |  | 
|  | 5 | The GNU C Library is free software; you can redistribute it and/or | 
|  | 6 | modify it under the terms of the GNU Lesser General Public | 
|  | 7 | License as published by the Free Software Foundation; either | 
|  | 8 | version 2.1 of the License, or (at your option) any later version. | 
|  | 9 |  | 
|  | 10 | The GNU C Library is distributed in the hope that it will be useful, | 
|  | 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 13 | Lesser General Public License for more details. | 
|  | 14 |  | 
|  | 15 | You should have received a copy of the GNU Lesser General Public | 
|  | 16 | License along with the GNU C Library; if not, see | 
|  | 17 | <http://www.gnu.org/licenses/>.  */ | 
|  | 18 |  | 
|  | 19 | #include <errno.h> | 
|  | 20 | #include <signal.h> | 
|  | 21 | #include <stdlib.h> | 
|  | 22 | #include "pthreadP.h" | 
|  | 23 | #include <atomic.h> | 
|  | 24 | #include <sysdep.h> | 
|  | 25 |  | 
|  | 26 |  | 
|  | 27 | int | 
|  | 28 | pthread_cancel (pthread_t th) | 
|  | 29 | { | 
|  | 30 | volatile struct pthread *pd = (volatile struct pthread *) th; | 
|  | 31 |  | 
|  | 32 | /* Make sure the descriptor is valid.  */ | 
|  | 33 | if (INVALID_TD_P (pd)) | 
|  | 34 | /* Not a valid thread handle.  */ | 
|  | 35 | return ESRCH; | 
|  | 36 |  | 
|  | 37 | #ifdef SHARED | 
|  | 38 | pthread_cancel_init (); | 
|  | 39 | #endif | 
|  | 40 | int result = 0; | 
|  | 41 | int oldval; | 
|  | 42 | int newval; | 
|  | 43 | do | 
|  | 44 | { | 
|  | 45 | again: | 
|  | 46 | oldval = pd->cancelhandling; | 
|  | 47 | newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; | 
|  | 48 |  | 
|  | 49 | /* Avoid doing unnecessary work.  The atomic operation can | 
|  | 50 | potentially be expensive if the bug has to be locked and | 
|  | 51 | remote cache lines have to be invalidated.  */ | 
|  | 52 | if (oldval == newval) | 
|  | 53 | break; | 
|  | 54 |  | 
|  | 55 | /* If the cancellation is handled asynchronously just send a | 
|  | 56 | signal.  We avoid this if possible since it's more | 
|  | 57 | expensive.  */ | 
|  | 58 | if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) | 
|  | 59 | { | 
|  | 60 | /* Mark the cancellation as "in progress".  */ | 
|  | 61 | if (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, | 
|  | 62 | oldval | CANCELING_BITMASK, | 
|  | 63 | oldval)) | 
|  | 64 | goto again; | 
|  | 65 |  | 
|  | 66 | #ifdef SIGCANCEL | 
|  | 67 | /* The cancellation handler will take care of marking the | 
|  | 68 | thread as canceled.  */ | 
|  | 69 | INTERNAL_SYSCALL_DECL (err); | 
|  | 70 |  | 
|  | 71 | /* One comment: The PID field in the TCB can temporarily be | 
|  | 72 | changed (in fork).  But this must not affect this code | 
|  | 73 | here.  Since this function would have to be called while | 
|  | 74 | the thread is executing fork, it would have to happen in | 
|  | 75 | a signal handler.  But this is no allowed, pthread_cancel | 
|  | 76 | is not guaranteed to be async-safe.  */ | 
|  | 77 | int val; | 
|  | 78 | val = INTERNAL_SYSCALL (tgkill, err, 3, | 
|  | 79 | THREAD_GETMEM (THREAD_SELF, pid), pd->tid, | 
|  | 80 | SIGCANCEL); | 
|  | 81 |  | 
|  | 82 | if (INTERNAL_SYSCALL_ERROR_P (val, err)) | 
|  | 83 | result = INTERNAL_SYSCALL_ERRNO (val, err); | 
|  | 84 | #else | 
|  | 85 | /* It should be impossible to get here at all, since | 
|  | 86 | pthread_setcanceltype should never have allowed | 
|  | 87 | PTHREAD_CANCEL_ASYNCHRONOUS to be set.  */ | 
|  | 88 | abort (); | 
|  | 89 | #endif | 
|  | 90 |  | 
|  | 91 | break; | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | /* A single-threaded process should be able to kill itself, since | 
|  | 95 | there is nothing in the POSIX specification that says that it | 
|  | 96 | cannot.  So we set multiple_threads to true so that cancellation | 
|  | 97 | points get executed.  */ | 
|  | 98 | THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1); | 
|  | 99 | #ifndef TLS_MULTIPLE_THREADS_IN_TCB | 
|  | 100 | __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1; | 
|  | 101 | #endif | 
|  | 102 | } | 
|  | 103 | /* Mark the thread as canceled.  This has to be done | 
|  | 104 | atomically since other bits could be modified as well.  */ | 
|  | 105 | while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval, | 
|  | 106 | oldval)); | 
|  | 107 |  | 
|  | 108 | return result; | 
|  | 109 | } | 
|  | 110 |  | 
|  | 111 | PTHREAD_STATIC_FN_REQUIRE (pthread_create) |