| 1 | /* Copyright (C) 2002-2023 Free Software Foundation, Inc. |
| 2 | This file is part of the GNU C Library. |
| 3 | |
| 4 | The GNU C Library is free software; you can redistribute it and/or |
| 5 | modify it under the terms of the GNU Lesser General Public |
| 6 | License as published by the Free Software Foundation; either |
| 7 | version 2.1 of the License, or (at your option) any later version. |
| 8 | |
| 9 | The GNU C Library is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | Lesser General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU Lesser General Public |
| 15 | License along with the GNU C Library; if not, see |
| 16 | <https://www.gnu.org/licenses/>. */ |
| 17 | |
| 18 | #include <errno.h> |
| 19 | #include <signal.h> |
| 20 | #include <stdlib.h> |
| 21 | #include "pthreadP.h" |
| 22 | #include <atomic.h> |
| 23 | #include <sysdep.h> |
| 24 | #include <unistd.h> |
| 25 | #include <unwind-link.h> |
| 26 | #include <stdio.h> |
| 27 | #include <gnu/lib-names.h> |
| 28 | #include <sys/single_threaded.h> |
| 29 | |
| 30 | /* For asynchronous cancellation we use a signal. */ |
| 31 | static void |
| 32 | sigcancel_handler (int sig, siginfo_t *si, void *ctx) |
| 33 | { |
| 34 | /* Safety check. It would be possible to call this function for |
| 35 | other signals and send a signal from another process. This is not |
| 36 | correct and might even be a security problem. Try to catch as |
| 37 | many incorrect invocations as possible. */ |
| 38 | if (sig != SIGCANCEL |
| 39 | || si->si_pid != __getpid() |
| 40 | || si->si_code != SI_TKILL) |
| 41 | return; |
| 42 | |
| 43 | struct pthread *self = THREAD_SELF; |
| 44 | |
| 45 | int oldval = atomic_load_relaxed (&self->cancelhandling); |
| 46 | while (1) |
| 47 | { |
| 48 | /* We are canceled now. When canceled by another thread this flag |
| 49 | is already set but if the signal is directly send (internally or |
| 50 | from another process) is has to be done here. */ |
| 51 | int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; |
| 52 | |
| 53 | if (oldval == newval || (oldval & EXITING_BITMASK) != 0) |
| 54 | /* Already canceled or exiting. */ |
| 55 | break; |
| 56 | |
| 57 | if (atomic_compare_exchange_weak_acquire (&self->cancelhandling, |
| 58 | &oldval, newval)) |
| 59 | { |
| 60 | self->result = PTHREAD_CANCELED; |
| 61 | |
| 62 | /* Make sure asynchronous cancellation is still enabled. */ |
| 63 | if ((oldval & CANCELTYPE_BITMASK) != 0) |
| 64 | /* Run the registered destructors and terminate the thread. */ |
| 65 | __do_cancel (); |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | int |
| 71 | __pthread_cancel (pthread_t th) |
| 72 | { |
| 73 | volatile struct pthread *pd = (volatile struct pthread *) th; |
| 74 | |
| 75 | if (pd->tid == 0) |
| 76 | /* The thread has already exited on the kernel side. Its outcome |
| 77 | (regular exit, other cancelation) has already been |
| 78 | determined. */ |
| 79 | return 0; |
| 80 | |
| 81 | static int init_sigcancel = 0; |
| 82 | if (atomic_load_relaxed (&init_sigcancel) == 0) |
| 83 | { |
| 84 | struct sigaction sa; |
| 85 | sa.sa_sigaction = sigcancel_handler; |
| 86 | /* The signal handle should be non-interruptible to avoid the risk of |
| 87 | spurious EINTR caused by SIGCANCEL sent to process or if |
| 88 | pthread_cancel() is called while cancellation is disabled in the |
| 89 | target thread. */ |
| 90 | sa.sa_flags = SA_SIGINFO | SA_RESTART; |
| 91 | __sigemptyset (&sa.sa_mask); |
| 92 | __libc_sigaction (SIGCANCEL, &sa, NULL); |
| 93 | atomic_store_relaxed (&init_sigcancel, 1); |
| 94 | } |
| 95 | |
| 96 | #ifdef SHARED |
| 97 | /* Trigger an error if libgcc_s cannot be loaded. */ |
| 98 | { |
| 99 | struct unwind_link *unwind_link = __libc_unwind_link_get (); |
| 100 | if (unwind_link == NULL) |
| 101 | __libc_fatal (LIBGCC_S_SO |
| 102 | " must be installed for pthread_cancel to work\n" ); |
| 103 | } |
| 104 | #endif |
| 105 | |
| 106 | /* Some syscalls are never restarted after being interrupted by a signal |
| 107 | handler, regardless of the use of SA_RESTART (they always fail with |
| 108 | EINTR). So pthread_cancel cannot send SIGCANCEL unless the cancellation |
| 109 | is enabled and set as asynchronous (in this case the cancellation will |
| 110 | be acted in the cancellation handler instead by the syscall wrapper). |
| 111 | Otherwise the target thread is set as 'cancelling' (CANCELING_BITMASK) |
| 112 | by atomically setting 'cancelhandling' and the cancelation will be acted |
| 113 | upon on next cancellation entrypoing in the target thread. |
| 114 | |
| 115 | It also requires to atomically check if cancellation is enabled and |
| 116 | asynchronous, so both cancellation state and type are tracked on |
| 117 | 'cancelhandling'. */ |
| 118 | |
| 119 | int result = 0; |
| 120 | int oldval = atomic_load_relaxed (&pd->cancelhandling); |
| 121 | int newval; |
| 122 | do |
| 123 | { |
| 124 | again: |
| 125 | newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; |
| 126 | if (oldval == newval) |
| 127 | break; |
| 128 | |
| 129 | /* If the cancellation is handled asynchronously just send a |
| 130 | signal. We avoid this if possible since it's more |
| 131 | expensive. */ |
| 132 | if (cancel_enabled_and_canceled_and_async (newval)) |
| 133 | { |
| 134 | /* Mark the cancellation as "in progress". */ |
| 135 | int newval2 = oldval | CANCELING_BITMASK; |
| 136 | if (!atomic_compare_exchange_weak_acquire (&pd->cancelhandling, |
| 137 | &oldval, newval2)) |
| 138 | goto again; |
| 139 | |
| 140 | if (pd == THREAD_SELF) |
| 141 | /* This is not merely an optimization: An application may |
| 142 | call pthread_cancel (pthread_self ()) without calling |
| 143 | pthread_create, so the signal handler may not have been |
| 144 | set up for a self-cancel. */ |
| 145 | { |
| 146 | pd->result = PTHREAD_CANCELED; |
| 147 | if ((newval & CANCELTYPE_BITMASK) != 0) |
| 148 | __do_cancel (); |
| 149 | } |
| 150 | else |
| 151 | /* The cancellation handler will take care of marking the |
| 152 | thread as canceled. */ |
| 153 | result = __pthread_kill_internal (th, SIGCANCEL); |
| 154 | |
| 155 | break; |
| 156 | } |
| 157 | |
| 158 | /* A single-threaded process should be able to kill itself, since |
| 159 | there is nothing in the POSIX specification that says that it |
| 160 | cannot. So we set multiple_threads to true so that cancellation |
| 161 | points get executed. */ |
| 162 | THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1); |
| 163 | #ifndef TLS_MULTIPLE_THREADS_IN_TCB |
| 164 | __libc_single_threaded_internal = 0; |
| 165 | #endif |
| 166 | } |
| 167 | while (!atomic_compare_exchange_weak_acquire (&pd->cancelhandling, &oldval, |
| 168 | newval)); |
| 169 | |
| 170 | return result; |
| 171 | } |
| 172 | versioned_symbol (libc, __pthread_cancel, pthread_cancel, GLIBC_2_34); |
| 173 | |
| 174 | #if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) |
| 175 | compat_symbol (libpthread, __pthread_cancel, pthread_cancel, GLIBC_2_0); |
| 176 | #endif |
| 177 | |
| 178 | /* Ensure that the unwinder is always linked in (the __pthread_unwind |
| 179 | reference from __do_cancel is weak). Use ___pthread_unwind_next |
| 180 | (three underscores) to produce a strong reference to the same |
| 181 | file. */ |
| 182 | PTHREAD_STATIC_FN_REQUIRE (___pthread_unwind_next) |
| 183 | |