15e53a4f9SPedro F. Giffuni /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 35e53a4f9SPedro F. Giffuni * 4df2cf821SDavid Xu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 5bb535300SJeff Roberson * All rights reserved. 6bb535300SJeff Roberson * 7bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 8bb535300SJeff Roberson * modification, are permitted provided that the following conditions 9bb535300SJeff Roberson * are met: 10bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 11df2cf821SDavid Xu * notice unmodified, this list of conditions, and the following 12df2cf821SDavid Xu * disclaimer. 13bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 14bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 15bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 16bb535300SJeff Roberson * 17df2cf821SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18df2cf821SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19df2cf821SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20df2cf821SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21df2cf821SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22df2cf821SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23df2cf821SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24df2cf821SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25df2cf821SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26df2cf821SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27bb535300SJeff Roberson */ 28bb535300SJeff Roberson 2932793011SKonstantin Belousov #include <sys/cdefs.h> 3032793011SKonstantin Belousov __FBSDID("$FreeBSD$"); 3132793011SKonstantin Belousov 3237a6356bSDavid Xu #include "namespace.h" 33bb535300SJeff Roberson #include <sys/param.h> 34fc908e50SKonstantin Belousov #include <sys/auxv.h> 35fc908e50SKonstantin Belousov #include <sys/elf.h> 36bb535300SJeff Roberson #include <sys/signalvar.h> 373d40192dSKonstantin Belousov #include <sys/syscall.h> 38bb535300SJeff Roberson #include <signal.h> 39a091d823SDavid Xu #include <errno.h> 4010280ca6SKonstantin Belousov #include <stdlib.h> 41a091d823SDavid Xu #include <string.h> 42bb535300SJeff Roberson #include <pthread.h> 4337a6356bSDavid Xu #include "un-namespace.h" 4402c3c858SDavid Xu #include "libc_private.h" 4589552201SMike Makonnen 468495e8b1SKonstantin Belousov #include "libc_private.h" 47bb535300SJeff Roberson #include "thr_private.h" 48bb535300SJeff Roberson 49bb535300SJeff Roberson /* #define DEBUG_SIGNAL */ 50bb535300SJeff Roberson #ifdef DEBUG_SIGNAL 51bb535300SJeff Roberson #define DBG_MSG stdout_debug 52bb535300SJeff Roberson #else 53bb535300SJeff Roberson #define DBG_MSG(x...) 54bb535300SJeff Roberson #endif 55bb535300SJeff Roberson 5602c3c858SDavid Xu struct usigaction { 5702c3c858SDavid Xu struct sigaction sigact; 5802c3c858SDavid Xu struct urwlock lock; 5902c3c858SDavid Xu }; 6002c3c858SDavid Xu 6102c3c858SDavid Xu static struct usigaction _thr_sigact[_SIG_MAXSIG]; 6202c3c858SDavid Xu 638495e8b1SKonstantin Belousov static inline struct usigaction * 648495e8b1SKonstantin Belousov __libc_sigaction_slot(int signo) 658495e8b1SKonstantin Belousov { 668495e8b1SKonstantin Belousov 678495e8b1SKonstantin Belousov return (&_thr_sigact[signo - 1]); 688495e8b1SKonstantin Belousov } 698495e8b1SKonstantin Belousov 7002c3c858SDavid Xu static void thr_sighandler(int, siginfo_t *, void *); 7102c3c858SDavid Xu static void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *); 7202c3c858SDavid Xu static void check_deferred_signal(struct pthread *); 7302c3c858SDavid Xu static void check_suspend(struct pthread *); 7402c3c858SDavid Xu static void check_cancel(struct pthread *curthread, ucontext_t *ucp); 7502c3c858SDavid Xu 76922d56f9SDavid Xu int _sigtimedwait(const sigset_t *set, siginfo_t *info, 77922d56f9SDavid Xu const struct timespec * timeout); 78922d56f9SDavid Xu int _sigwaitinfo(const sigset_t *set, siginfo_t *info); 79922d56f9SDavid Xu int _sigwait(const sigset_t *set, int *sig); 805cf22195SDavid Xu int _setcontext(const ucontext_t *); 815cf22195SDavid Xu int _swapcontext(ucontext_t *, const ucontext_t *); 8237a6356bSDavid Xu 8302c3c858SDavid Xu static const sigset_t _thr_deferset={{ 8402c3c858SDavid Xu 0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)| 8502c3c858SDavid Xu _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)), 8602c3c858SDavid Xu 0xffffffff, 8702c3c858SDavid Xu 0xffffffff, 8802c3c858SDavid Xu 0xffffffff}}; 8902c3c858SDavid Xu 9002c3c858SDavid Xu static const sigset_t _thr_maskset={{ 9102c3c858SDavid Xu 0xffffffff, 9202c3c858SDavid Xu 0xffffffff, 9302c3c858SDavid Xu 0xffffffff, 9402c3c858SDavid Xu 0xffffffff}}; 9502c3c858SDavid Xu 96fc908e50SKonstantin Belousov static void 97fc908e50SKonstantin Belousov thr_signal_block_slow(struct pthread *curthread) 9802c3c858SDavid Xu { 9902c3c858SDavid Xu if (curthread->sigblock > 0) { 10002c3c858SDavid Xu curthread->sigblock++; 10102c3c858SDavid Xu return; 10202c3c858SDavid Xu } 10302c3c858SDavid Xu __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask); 10402c3c858SDavid Xu curthread->sigblock++; 10502c3c858SDavid Xu } 10602c3c858SDavid Xu 107fc908e50SKonstantin Belousov static void 108fc908e50SKonstantin Belousov thr_signal_unblock_slow(struct pthread *curthread) 10902c3c858SDavid Xu { 11002c3c858SDavid Xu if (--curthread->sigblock == 0) 11102c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 11202c3c858SDavid Xu } 11302c3c858SDavid Xu 114fc908e50SKonstantin Belousov static void 115fc908e50SKonstantin Belousov thr_signal_block_fast(struct pthread *curthread) 116fc908e50SKonstantin Belousov { 117fc908e50SKonstantin Belousov atomic_add_32(&curthread->fsigblock, SIGFASTBLOCK_INC); 118fc908e50SKonstantin Belousov } 119fc908e50SKonstantin Belousov 120fc908e50SKonstantin Belousov static void 121fc908e50SKonstantin Belousov thr_signal_unblock_fast(struct pthread *curthread) 122fc908e50SKonstantin Belousov { 123fc908e50SKonstantin Belousov uint32_t oldval; 124fc908e50SKonstantin Belousov 125fc908e50SKonstantin Belousov oldval = atomic_fetchadd_32(&curthread->fsigblock, -SIGFASTBLOCK_INC); 126fc908e50SKonstantin Belousov if (oldval == (SIGFASTBLOCK_PEND | SIGFASTBLOCK_INC)) 127fc908e50SKonstantin Belousov __sys_sigfastblock(SIGFASTBLOCK_UNBLOCK, NULL); 128fc908e50SKonstantin Belousov } 129fc908e50SKonstantin Belousov 130fc908e50SKonstantin Belousov static bool fast_sigblock; 131fc908e50SKonstantin Belousov 132fc908e50SKonstantin Belousov void 133fc908e50SKonstantin Belousov _thr_signal_block(struct pthread *curthread) 134fc908e50SKonstantin Belousov { 135fc908e50SKonstantin Belousov if (fast_sigblock) 136fc908e50SKonstantin Belousov thr_signal_block_fast(curthread); 137fc908e50SKonstantin Belousov else 138fc908e50SKonstantin Belousov thr_signal_block_slow(curthread); 139fc908e50SKonstantin Belousov } 140fc908e50SKonstantin Belousov 141fc908e50SKonstantin Belousov void 142fc908e50SKonstantin Belousov _thr_signal_unblock(struct pthread *curthread) 143fc908e50SKonstantin Belousov { 144fc908e50SKonstantin Belousov if (fast_sigblock) 145fc908e50SKonstantin Belousov thr_signal_unblock_fast(curthread); 146fc908e50SKonstantin Belousov else 147fc908e50SKonstantin Belousov thr_signal_unblock_slow(curthread); 148fc908e50SKonstantin Belousov } 149fc908e50SKonstantin Belousov 150fc908e50SKonstantin Belousov void 151fc908e50SKonstantin Belousov _thr_signal_block_check_fast(void) 152fc908e50SKonstantin Belousov { 153fc908e50SKonstantin Belousov int bsdflags, error; 154fc908e50SKonstantin Belousov 155fc908e50SKonstantin Belousov error = elf_aux_info(AT_BSDFLAGS, &bsdflags, sizeof(bsdflags)); 156fc908e50SKonstantin Belousov if (error != 0) 157fc908e50SKonstantin Belousov return; 158fc908e50SKonstantin Belousov fast_sigblock = (bsdflags & ELF_BSDF_SIGFASTBLK) != 0; 159fc908e50SKonstantin Belousov } 160fc908e50SKonstantin Belousov 161fc908e50SKonstantin Belousov void 162fc908e50SKonstantin Belousov _thr_signal_block_setup(struct pthread *curthread) 163fc908e50SKonstantin Belousov { 164fc908e50SKonstantin Belousov if (!fast_sigblock) 165fc908e50SKonstantin Belousov return; 166fc908e50SKonstantin Belousov __sys_sigfastblock(SIGFASTBLOCK_SETPTR, &curthread->fsigblock); 167fc908e50SKonstantin Belousov } 168fc908e50SKonstantin Belousov 16902c3c858SDavid Xu int 17002c3c858SDavid Xu _thr_send_sig(struct pthread *thread, int sig) 17102c3c858SDavid Xu { 17202c3c858SDavid Xu return thr_kill(thread->tid, sig); 17302c3c858SDavid Xu } 17402c3c858SDavid Xu 17502c3c858SDavid Xu static inline void 1765cf22195SDavid Xu remove_thr_signals(sigset_t *set) 1775cf22195SDavid Xu { 1785cf22195SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) 1795cf22195SDavid Xu SIGDELSET(*set, SIGCANCEL); 1805cf22195SDavid Xu } 1815cf22195SDavid Xu 1825cf22195SDavid Xu static const sigset_t * 1835cf22195SDavid Xu thr_remove_thr_signals(const sigset_t *set, sigset_t *newset) 1845cf22195SDavid Xu { 1855cf22195SDavid Xu *newset = *set; 18602c3c858SDavid Xu remove_thr_signals(newset); 18702c3c858SDavid Xu return (newset); 1885cf22195SDavid Xu } 1896fdfcacbSDavid Xu 190a091d823SDavid Xu static void 19137a6356bSDavid Xu sigcancel_handler(int sig __unused, 19202c3c858SDavid Xu siginfo_t *info __unused, ucontext_t *ucp) 193a091d823SDavid Xu { 194a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 19502c3c858SDavid Xu int err; 196a091d823SDavid Xu 19702c3c858SDavid Xu if (THR_IN_CRITICAL(curthread)) 19802c3c858SDavid Xu return; 19902c3c858SDavid Xu err = errno; 20002c3c858SDavid Xu check_suspend(curthread); 20102c3c858SDavid Xu check_cancel(curthread, ucp); 20202c3c858SDavid Xu errno = err; 20302c3c858SDavid Xu } 20402c3c858SDavid Xu 2058495e8b1SKonstantin Belousov typedef void (*ohandler)(int sig, int code, struct sigcontext *scp, 2068495e8b1SKonstantin Belousov char *addr, __sighandler_t *catcher); 20702c3c858SDavid Xu 20802c3c858SDavid Xu /* 20902c3c858SDavid Xu * The signal handler wrapper is entered with all signal masked. 21002c3c858SDavid Xu */ 21102c3c858SDavid Xu static void 21202c3c858SDavid Xu thr_sighandler(int sig, siginfo_t *info, void *_ucp) 21302c3c858SDavid Xu { 2148495e8b1SKonstantin Belousov struct pthread *curthread; 2158495e8b1SKonstantin Belousov ucontext_t *ucp; 21602c3c858SDavid Xu struct sigaction act; 2178495e8b1SKonstantin Belousov struct usigaction *usa; 21802c3c858SDavid Xu int err; 21902c3c858SDavid Xu 22002c3c858SDavid Xu err = errno; 2218495e8b1SKonstantin Belousov curthread = _get_curthread(); 2228495e8b1SKonstantin Belousov ucp = _ucp; 2238495e8b1SKonstantin Belousov usa = __libc_sigaction_slot(sig); 2248495e8b1SKonstantin Belousov _thr_rwl_rdlock(&usa->lock); 2258495e8b1SKonstantin Belousov act = usa->sigact; 2268495e8b1SKonstantin Belousov _thr_rwl_unlock(&usa->lock); 22702c3c858SDavid Xu errno = err; 2280a9655a0SKonstantin Belousov curthread->deferred_run = 0; 22902c3c858SDavid Xu 23002c3c858SDavid Xu /* 23102c3c858SDavid Xu * if a thread is in critical region, for example it holds low level locks, 23202c3c858SDavid Xu * try to defer the signal processing, however if the signal is synchronous 23302c3c858SDavid Xu * signal, it means a bad thing has happened, this is a programming error, 23402c3c858SDavid Xu * resuming fault point can not help anything (normally causes deadloop), 23502c3c858SDavid Xu * so here we let user code handle it immediately. 23602c3c858SDavid Xu */ 23702c3c858SDavid Xu if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) { 23802c3c858SDavid Xu memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction)); 23902c3c858SDavid Xu memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t)); 24002c3c858SDavid Xu curthread->deferred_sigmask = ucp->uc_sigmask; 24102c3c858SDavid Xu /* mask all signals, we will restore it later. */ 24202c3c858SDavid Xu ucp->uc_sigmask = _thr_deferset; 24302c3c858SDavid Xu return; 24402c3c858SDavid Xu } 24502c3c858SDavid Xu 24602c3c858SDavid Xu handle_signal(&act, sig, info, ucp); 24702c3c858SDavid Xu } 24802c3c858SDavid Xu 24902c3c858SDavid Xu static void 25002c3c858SDavid Xu handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) 25102c3c858SDavid Xu { 25202c3c858SDavid Xu struct pthread *curthread = _get_curthread(); 25302c3c858SDavid Xu ucontext_t uc2; 25402c3c858SDavid Xu __siginfohandler_t *sigfunc; 25502c3c858SDavid Xu int cancel_point; 25602c3c858SDavid Xu int cancel_async; 25702c3c858SDavid Xu int cancel_enable; 25802c3c858SDavid Xu int in_sigsuspend; 25902c3c858SDavid Xu int err; 26002c3c858SDavid Xu 26102c3c858SDavid Xu /* add previous level mask */ 26202c3c858SDavid Xu SIGSETOR(actp->sa_mask, ucp->uc_sigmask); 26302c3c858SDavid Xu 26402c3c858SDavid Xu /* add this signal's mask */ 26502c3c858SDavid Xu if (!(actp->sa_flags & SA_NODEFER)) 26602c3c858SDavid Xu SIGADDSET(actp->sa_mask, sig); 26702c3c858SDavid Xu 26802c3c858SDavid Xu in_sigsuspend = curthread->in_sigsuspend; 26902c3c858SDavid Xu curthread->in_sigsuspend = 0; 27002c3c858SDavid Xu 27102c3c858SDavid Xu /* 2725b1dd970SKonstantin Belousov * If thread is in deferred cancellation mode, disable cancellation 27302c3c858SDavid Xu * in signal handler. 2745b1dd970SKonstantin Belousov * If user signal handler calls a cancellation point function, e.g, 27502c3c858SDavid Xu * it calls write() to write data to file, because write() is a 27602c3c858SDavid Xu * cancellation point, the thread is immediately cancelled if 27702c3c858SDavid Xu * cancellation is pending, to avoid this problem while thread is in 27802c3c858SDavid Xu * deferring mode, cancellation is temporarily disabled. 27902c3c858SDavid Xu */ 28002c3c858SDavid Xu cancel_point = curthread->cancel_point; 28102c3c858SDavid Xu cancel_async = curthread->cancel_async; 28202c3c858SDavid Xu cancel_enable = curthread->cancel_enable; 28302c3c858SDavid Xu curthread->cancel_point = 0; 28402c3c858SDavid Xu if (!cancel_async) 28502c3c858SDavid Xu curthread->cancel_enable = 0; 28602c3c858SDavid Xu 28702c3c858SDavid Xu /* restore correct mask before calling user handler */ 28802c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL); 28902c3c858SDavid Xu 29002c3c858SDavid Xu sigfunc = actp->sa_sigaction; 29102c3c858SDavid Xu 29202c3c858SDavid Xu /* 29302c3c858SDavid Xu * We have already reset cancellation point flags, so if user's code 29402c3c858SDavid Xu * longjmp()s out of its signal handler, wish its jmpbuf was set 29502c3c858SDavid Xu * outside of a cancellation point, in most cases, this would be 2965b1dd970SKonstantin Belousov * true. However, there is no way to save cancel_enable in jmpbuf, 29702c3c858SDavid Xu * so after setjmps() returns once more, the user code may need to 29802c3c858SDavid Xu * re-set cancel_enable flag by calling pthread_setcancelstate(). 29902c3c858SDavid Xu */ 3008495e8b1SKonstantin Belousov if ((actp->sa_flags & SA_SIGINFO) != 0) { 3018495e8b1SKonstantin Belousov sigfunc(sig, info, ucp); 3028495e8b1SKonstantin Belousov } else { 3038495e8b1SKonstantin Belousov ((ohandler)sigfunc)(sig, info->si_code, 3048495e8b1SKonstantin Belousov (struct sigcontext *)ucp, info->si_addr, 3058495e8b1SKonstantin Belousov (__sighandler_t *)sigfunc); 30602c3c858SDavid Xu } 30702c3c858SDavid Xu err = errno; 30802c3c858SDavid Xu 30902c3c858SDavid Xu curthread->in_sigsuspend = in_sigsuspend; 31002c3c858SDavid Xu curthread->cancel_point = cancel_point; 31102c3c858SDavid Xu curthread->cancel_enable = cancel_enable; 31202c3c858SDavid Xu 31302c3c858SDavid Xu memcpy(&uc2, ucp, sizeof(uc2)); 31402c3c858SDavid Xu SIGDELSET(uc2.uc_sigmask, SIGCANCEL); 31502c3c858SDavid Xu 31602c3c858SDavid Xu /* reschedule cancellation */ 31702c3c858SDavid Xu check_cancel(curthread, &uc2); 31802c3c858SDavid Xu errno = err; 3193d40192dSKonstantin Belousov syscall(SYS_sigreturn, &uc2); 320bc414752SDavid Xu } 321bc414752SDavid Xu 322bc414752SDavid Xu void 323bc414752SDavid Xu _thr_ast(struct pthread *curthread) 324bc414752SDavid Xu { 325635f917aSDavid Xu 32602c3c858SDavid Xu if (!THR_IN_CRITICAL(curthread)) { 32702c3c858SDavid Xu check_deferred_signal(curthread); 32802c3c858SDavid Xu check_suspend(curthread); 32902c3c858SDavid Xu check_cancel(curthread, NULL); 33002c3c858SDavid Xu } 33102c3c858SDavid Xu } 33202c3c858SDavid Xu 33302c3c858SDavid Xu /* reschedule cancellation */ 33402c3c858SDavid Xu static void 33502c3c858SDavid Xu check_cancel(struct pthread *curthread, ucontext_t *ucp) 33602c3c858SDavid Xu { 33702c3c858SDavid Xu 33881f3e99cSDavid Xu if (__predict_true(!curthread->cancel_pending || 33981f3e99cSDavid Xu !curthread->cancel_enable || curthread->no_cancel)) 340635f917aSDavid Xu return; 341635f917aSDavid Xu 342635f917aSDavid Xu /* 343635f917aSDavid Xu * Otherwise, we are in defer mode, and we are at 344635f917aSDavid Xu * cancel point, tell kernel to not block the current 345635f917aSDavid Xu * thread on next cancelable system call. 346635f917aSDavid Xu * 34702c3c858SDavid Xu * There are three cases we should call thr_wake() to 34802c3c858SDavid Xu * turn on TDP_WAKEUP or send SIGCANCEL in kernel: 349635f917aSDavid Xu * 1) we are going to call a cancelable system call, 350635f917aSDavid Xu * non-zero cancel_point means we are already in 351635f917aSDavid Xu * cancelable state, next system call is cancelable. 352635f917aSDavid Xu * 2) because _thr_ast() may be called by 353635f917aSDavid Xu * THR_CRITICAL_LEAVE() which is used by rtld rwlock 354635f917aSDavid Xu * and any libthr internal locks, when rtld rwlock 355c5e7289cSKonstantin Belousov * is used, it is mostly caused by an unresolved PLT. 356c5e7289cSKonstantin Belousov * Those routines may clear the TDP_WAKEUP flag by 357635f917aSDavid Xu * invoking some system calls, in those cases, we 358635f917aSDavid Xu * also should reenable the flag. 35902c3c858SDavid Xu * 3) thread is in sigsuspend(), and the syscall insists 36002c3c858SDavid Xu * on getting a signal before it agrees to return. 361635f917aSDavid Xu */ 362635f917aSDavid Xu if (curthread->cancel_point) { 36302c3c858SDavid Xu if (curthread->in_sigsuspend && ucp) { 36402c3c858SDavid Xu SIGADDSET(ucp->uc_sigmask, SIGCANCEL); 36502c3c858SDavid Xu curthread->unblock_sigcancel = 1; 36602c3c858SDavid Xu _thr_send_sig(curthread, SIGCANCEL); 36702c3c858SDavid Xu } else 368635f917aSDavid Xu thr_wake(curthread->tid); 36981f3e99cSDavid Xu } else if (curthread->cancel_async) { 37081f3e99cSDavid Xu /* 37181f3e99cSDavid Xu * asynchronous cancellation mode, act upon 37281f3e99cSDavid Xu * immediately. 37381f3e99cSDavid Xu */ 37481f3e99cSDavid Xu _pthread_exit_mask(PTHREAD_CANCELED, 37581f3e99cSDavid Xu ucp? &ucp->uc_sigmask : NULL); 376635f917aSDavid Xu } 377635f917aSDavid Xu } 378635f917aSDavid Xu 37902c3c858SDavid Xu static void 38002c3c858SDavid Xu check_deferred_signal(struct pthread *curthread) 38102c3c858SDavid Xu { 38210280ca6SKonstantin Belousov ucontext_t *uc; 38302c3c858SDavid Xu struct sigaction act; 38402c3c858SDavid Xu siginfo_t info; 38591ddaeb7SKonstantin Belousov int uc_len; 38602c3c858SDavid Xu 3870a9655a0SKonstantin Belousov if (__predict_true(curthread->deferred_siginfo.si_signo == 0 || 3880a9655a0SKonstantin Belousov curthread->deferred_run)) 38902c3c858SDavid Xu return; 39010280ca6SKonstantin Belousov 3910a9655a0SKonstantin Belousov curthread->deferred_run = 1; 39255a1911eSKonstantin Belousov uc_len = __getcontextx_size(); 39355a1911eSKonstantin Belousov uc = alloca(uc_len); 39455a1911eSKonstantin Belousov getcontext(uc); 3950a9655a0SKonstantin Belousov if (curthread->deferred_siginfo.si_signo == 0) { 3960a9655a0SKonstantin Belousov curthread->deferred_run = 0; 39755a1911eSKonstantin Belousov return; 3980a9655a0SKonstantin Belousov } 39955a1911eSKonstantin Belousov __fillcontextx2((char *)uc); 40002c3c858SDavid Xu act = curthread->deferred_sigact; 40110280ca6SKonstantin Belousov uc->uc_sigmask = curthread->deferred_sigmask; 40202c3c858SDavid Xu memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t)); 40302c3c858SDavid Xu /* remove signal */ 40402c3c858SDavid Xu curthread->deferred_siginfo.si_signo = 0; 40510280ca6SKonstantin Belousov handle_signal(&act, info.si_signo, &info, uc); 40602c3c858SDavid Xu } 407a091d823SDavid Xu 40802c3c858SDavid Xu static void 40902c3c858SDavid Xu check_suspend(struct pthread *curthread) 410a091d823SDavid Xu { 4118d6a11a0SDavid Xu uint32_t cycle; 41202c3c858SDavid Xu 41302c3c858SDavid Xu if (__predict_true((curthread->flags & 41402c3c858SDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 41502c3c858SDavid Xu != THR_FLAGS_NEED_SUSPEND)) 41602c3c858SDavid Xu return; 417a7b84c65SDavid Xu if (curthread == _single_thread) 418a7b84c65SDavid Xu return; 4192ea1f90aSDavid Xu if (curthread->force_exit) 4202ea1f90aSDavid Xu return; 4212ea1f90aSDavid Xu 422bc414752SDavid Xu /* 423bc414752SDavid Xu * Blocks SIGCANCEL which other threads must send. 424bc414752SDavid Xu */ 425a091d823SDavid Xu _thr_signal_block(curthread); 426bc414752SDavid Xu 427bc414752SDavid Xu /* 428bc414752SDavid Xu * Increase critical_count, here we don't use THR_LOCK/UNLOCK 429bc414752SDavid Xu * because we are leaf code, we don't want to recursively call 430bc414752SDavid Xu * ourself. 431bc414752SDavid Xu */ 432bc414752SDavid Xu curthread->critical_count++; 433bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 434321e2a00SKonstantin Belousov while ((curthread->flags & THR_FLAGS_NEED_SUSPEND) != 0) { 435bc414752SDavid Xu curthread->cycle++; 436a091d823SDavid Xu cycle = curthread->cycle; 437bc414752SDavid Xu 438bc414752SDavid Xu /* Wake the thread suspending us. */ 4398d6a11a0SDavid Xu _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 440bc414752SDavid Xu 441bc414752SDavid Xu /* 442bc414752SDavid Xu * if we are from pthread_exit, we don't want to 443bc414752SDavid Xu * suspend, just go and die. 444bc414752SDavid Xu */ 445bc414752SDavid Xu if (curthread->state == PS_DEAD) 446bc414752SDavid Xu break; 447bc414752SDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED; 448bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 4498d6a11a0SDavid Xu _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0); 450bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 451a091d823SDavid Xu } 452bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 453bc414752SDavid Xu curthread->critical_count--; 454bc414752SDavid Xu 455a091d823SDavid Xu _thr_signal_unblock(curthread); 456a091d823SDavid Xu } 457a091d823SDavid Xu 458a091d823SDavid Xu void 4598495e8b1SKonstantin Belousov _thr_signal_init(int dlopened) 460a091d823SDavid Xu { 4618495e8b1SKonstantin Belousov struct sigaction act, nact, oact; 4628495e8b1SKonstantin Belousov struct usigaction *usa; 4638495e8b1SKonstantin Belousov sigset_t oldset; 4648495e8b1SKonstantin Belousov int sig, error; 4658495e8b1SKonstantin Belousov 4668495e8b1SKonstantin Belousov if (dlopened) { 4678495e8b1SKonstantin Belousov __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 4688495e8b1SKonstantin Belousov for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 4698495e8b1SKonstantin Belousov if (sig == SIGCANCEL) 4708495e8b1SKonstantin Belousov continue; 4718495e8b1SKonstantin Belousov error = __sys_sigaction(sig, NULL, &oact); 4728495e8b1SKonstantin Belousov if (error == -1 || oact.sa_handler == SIG_DFL || 4738495e8b1SKonstantin Belousov oact.sa_handler == SIG_IGN) 4748495e8b1SKonstantin Belousov continue; 4758495e8b1SKonstantin Belousov usa = __libc_sigaction_slot(sig); 4768495e8b1SKonstantin Belousov usa->sigact = oact; 4778495e8b1SKonstantin Belousov nact = oact; 4788495e8b1SKonstantin Belousov remove_thr_signals(&usa->sigact.sa_mask); 4798495e8b1SKonstantin Belousov nact.sa_flags &= ~SA_NODEFER; 4808495e8b1SKonstantin Belousov nact.sa_flags |= SA_SIGINFO; 4818495e8b1SKonstantin Belousov nact.sa_sigaction = thr_sighandler; 4828495e8b1SKonstantin Belousov nact.sa_mask = _thr_maskset; 4838495e8b1SKonstantin Belousov (void)__sys_sigaction(sig, &nact, NULL); 4848495e8b1SKonstantin Belousov } 4858495e8b1SKonstantin Belousov __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 4868495e8b1SKonstantin Belousov } 487a091d823SDavid Xu 48802c3c858SDavid Xu /* Install SIGCANCEL handler. */ 48902c3c858SDavid Xu SIGFILLSET(act.sa_mask); 49002c3c858SDavid Xu act.sa_flags = SA_SIGINFO; 491a091d823SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 492a091d823SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL); 49302c3c858SDavid Xu 49402c3c858SDavid Xu /* Unblock SIGCANCEL */ 49502c3c858SDavid Xu SIGEMPTYSET(act.sa_mask); 49602c3c858SDavid Xu SIGADDSET(act.sa_mask, SIGCANCEL); 49702c3c858SDavid Xu __sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL); 49802c3c858SDavid Xu } 49902c3c858SDavid Xu 50002c3c858SDavid Xu void 501d2335a57SEric van Gyzen _thr_sigact_unload(struct dl_phdr_info *phdr_info __unused) 50202c3c858SDavid Xu { 503cb4a1047SDavid Xu #if 0 50421a9296fSDavid Xu struct pthread *curthread = _get_curthread(); 50502c3c858SDavid Xu struct urwlock *rwlp; 50602c3c858SDavid Xu struct sigaction *actp; 5078495e8b1SKonstantin Belousov struct usigaction *usa; 50802c3c858SDavid Xu struct sigaction kact; 50902c3c858SDavid Xu void (*handler)(int); 51002c3c858SDavid Xu int sig; 51102c3c858SDavid Xu 51221a9296fSDavid Xu _thr_signal_block(curthread); 513cb4a1047SDavid Xu for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 5148495e8b1SKonstantin Belousov usa = __libc_sigaction_slot(sig); 5158495e8b1SKonstantin Belousov actp = &usa->sigact; 51602c3c858SDavid Xu retry: 51702c3c858SDavid Xu handler = actp->sa_handler; 51802c3c858SDavid Xu if (handler != SIG_DFL && handler != SIG_IGN && 51902c3c858SDavid Xu __elf_phdr_match_addr(phdr_info, handler)) { 5208495e8b1SKonstantin Belousov rwlp = &usa->lock; 52102c3c858SDavid Xu _thr_rwl_wrlock(rwlp); 52202c3c858SDavid Xu if (handler != actp->sa_handler) { 52302c3c858SDavid Xu _thr_rwl_unlock(rwlp); 52402c3c858SDavid Xu goto retry; 52502c3c858SDavid Xu } 52602c3c858SDavid Xu actp->sa_handler = SIG_DFL; 52702c3c858SDavid Xu actp->sa_flags = SA_SIGINFO; 52802c3c858SDavid Xu SIGEMPTYSET(actp->sa_mask); 52902c3c858SDavid Xu if (__sys_sigaction(sig, NULL, &kact) == 0 && 53002c3c858SDavid Xu kact.sa_handler != SIG_DFL && 53102c3c858SDavid Xu kact.sa_handler != SIG_IGN) 53202c3c858SDavid Xu __sys_sigaction(sig, actp, NULL); 53302c3c858SDavid Xu _thr_rwl_unlock(rwlp); 53402c3c858SDavid Xu } 53502c3c858SDavid Xu } 53621a9296fSDavid Xu _thr_signal_unblock(curthread); 537cb4a1047SDavid Xu #endif 53802c3c858SDavid Xu } 53902c3c858SDavid Xu 54002c3c858SDavid Xu void 54102c3c858SDavid Xu _thr_signal_prefork(void) 54202c3c858SDavid Xu { 54302c3c858SDavid Xu int i; 54402c3c858SDavid Xu 54591792417SJilles Tjoelker for (i = 1; i <= _SIG_MAXSIG; ++i) 5468495e8b1SKonstantin Belousov _thr_rwl_rdlock(&__libc_sigaction_slot(i)->lock); 54702c3c858SDavid Xu } 54802c3c858SDavid Xu 54902c3c858SDavid Xu void 55002c3c858SDavid Xu _thr_signal_postfork(void) 55102c3c858SDavid Xu { 55202c3c858SDavid Xu int i; 55302c3c858SDavid Xu 55491792417SJilles Tjoelker for (i = 1; i <= _SIG_MAXSIG; ++i) 5558495e8b1SKonstantin Belousov _thr_rwl_unlock(&__libc_sigaction_slot(i)->lock); 55602c3c858SDavid Xu } 55702c3c858SDavid Xu 55802c3c858SDavid Xu void 55902c3c858SDavid Xu _thr_signal_postfork_child(void) 56002c3c858SDavid Xu { 56102c3c858SDavid Xu int i; 56202c3c858SDavid Xu 5638495e8b1SKonstantin Belousov for (i = 1; i <= _SIG_MAXSIG; ++i) { 5648495e8b1SKonstantin Belousov bzero(&__libc_sigaction_slot(i) -> lock, 5658495e8b1SKonstantin Belousov sizeof(struct urwlock)); 5668495e8b1SKonstantin Belousov } 567a091d823SDavid Xu } 568a091d823SDavid Xu 569a091d823SDavid Xu void 570a091d823SDavid Xu _thr_signal_deinit(void) 571a091d823SDavid Xu { 572a091d823SDavid Xu } 573a091d823SDavid Xu 57405c3a5eaSDavid Xu int 5758495e8b1SKonstantin Belousov __thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) 576a091d823SDavid Xu { 57702c3c858SDavid Xu struct sigaction newact, oldact, oldact2; 57802c3c858SDavid Xu sigset_t oldset; 5798495e8b1SKonstantin Belousov struct usigaction *usa; 5808495e8b1SKonstantin Belousov int ret, err; 58102c3c858SDavid Xu 582b144e48bSKonstantin Belousov if (!_SIG_VALID(sig) || sig == SIGCANCEL) { 583a091d823SDavid Xu errno = EINVAL; 584a091d823SDavid Xu return (-1); 585a091d823SDavid Xu } 586a091d823SDavid Xu 5878495e8b1SKonstantin Belousov ret = 0; 5888495e8b1SKonstantin Belousov err = 0; 5898495e8b1SKonstantin Belousov usa = __libc_sigaction_slot(sig); 59002c3c858SDavid Xu 59102c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 5928495e8b1SKonstantin Belousov _thr_rwl_wrlock(&usa->lock); 59302c3c858SDavid Xu 59402c3c858SDavid Xu if (act != NULL) { 5958495e8b1SKonstantin Belousov oldact2 = usa->sigact; 5968495e8b1SKonstantin Belousov newact = *act; 59702c3c858SDavid Xu 59802c3c858SDavid Xu /* 59902c3c858SDavid Xu * if a new sig handler is SIG_DFL or SIG_IGN, 6008495e8b1SKonstantin Belousov * don't remove old handler from __libc_sigact[], 60102c3c858SDavid Xu * so deferred signals still can use the handlers, 60202c3c858SDavid Xu * multiple threads invoking sigaction itself is 60302c3c858SDavid Xu * a race condition, so it is not a problem. 60402c3c858SDavid Xu */ 60502c3c858SDavid Xu if (newact.sa_handler != SIG_DFL && 60602c3c858SDavid Xu newact.sa_handler != SIG_IGN) { 6078495e8b1SKonstantin Belousov usa->sigact = newact; 6088495e8b1SKonstantin Belousov remove_thr_signals(&usa->sigact.sa_mask); 60902c3c858SDavid Xu newact.sa_flags &= ~SA_NODEFER; 61002c3c858SDavid Xu newact.sa_flags |= SA_SIGINFO; 61102c3c858SDavid Xu newact.sa_sigaction = thr_sighandler; 61202c3c858SDavid Xu newact.sa_mask = _thr_maskset; /* mask all signals */ 61302c3c858SDavid Xu } 6148495e8b1SKonstantin Belousov ret = __sys_sigaction(sig, &newact, &oldact); 6158495e8b1SKonstantin Belousov if (ret == -1) { 61602c3c858SDavid Xu err = errno; 6178495e8b1SKonstantin Belousov usa->sigact = oldact2; 61802c3c858SDavid Xu } 61902c3c858SDavid Xu } else if (oact != NULL) { 62002c3c858SDavid Xu ret = __sys_sigaction(sig, NULL, &oldact); 62102c3c858SDavid Xu err = errno; 62202c3c858SDavid Xu } 62302c3c858SDavid Xu 6248495e8b1SKonstantin Belousov if (oldact.sa_handler != SIG_DFL && oldact.sa_handler != SIG_IGN) { 6256ed79f06SDavid Xu if (act != NULL) 6266ed79f06SDavid Xu oldact = oldact2; 6276ed79f06SDavid Xu else if (oact != NULL) 6288495e8b1SKonstantin Belousov oldact = usa->sigact; 62902c3c858SDavid Xu } 63002c3c858SDavid Xu 6318495e8b1SKonstantin Belousov _thr_rwl_unlock(&usa->lock); 63202c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 63302c3c858SDavid Xu 63402c3c858SDavid Xu if (ret == 0) { 63502c3c858SDavid Xu if (oact != NULL) 63602c3c858SDavid Xu *oact = oldact; 63702c3c858SDavid Xu } else { 63802c3c858SDavid Xu errno = err; 63902c3c858SDavid Xu } 64002c3c858SDavid Xu return (ret); 641a091d823SDavid Xu } 642a091d823SDavid Xu 643a091d823SDavid Xu int 6448495e8b1SKonstantin Belousov __thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset) 645a091d823SDavid Xu { 646a091d823SDavid Xu const sigset_t *p = set; 647a091d823SDavid Xu sigset_t newset; 648a091d823SDavid Xu 649a091d823SDavid Xu if (how != SIG_UNBLOCK) { 650a091d823SDavid Xu if (set != NULL) { 651a091d823SDavid Xu newset = *set; 652a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 653a091d823SDavid Xu p = &newset; 654a091d823SDavid Xu } 655a091d823SDavid Xu } 656a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 657a091d823SDavid Xu } 658a091d823SDavid Xu 6590ab1bfc7SKonstantin Belousov __weak_reference(_thr_sigmask, pthread_sigmask); 6600ab1bfc7SKonstantin Belousov __weak_reference(_thr_sigmask, _pthread_sigmask); 661bb535300SJeff Roberson 662bb535300SJeff Roberson int 6630ab1bfc7SKonstantin Belousov _thr_sigmask(int how, const sigset_t *set, sigset_t *oset) 664bb535300SJeff Roberson { 6659e8bff64SKonstantin Belousov 6669e8bff64SKonstantin Belousov if (__thr_sigprocmask(how, set, oset)) 667a091d823SDavid Xu return (errno); 668a091d823SDavid Xu return (0); 669bb535300SJeff Roberson } 670bb535300SJeff Roberson 671bb535300SJeff Roberson int 672a091d823SDavid Xu _sigsuspend(const sigset_t * set) 673bb535300SJeff Roberson { 67405c3a5eaSDavid Xu sigset_t newset; 67505c3a5eaSDavid Xu 67682746ea5SDavid Xu return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset))); 67705c3a5eaSDavid Xu } 67805c3a5eaSDavid Xu 67905c3a5eaSDavid Xu int 6808495e8b1SKonstantin Belousov __thr_sigsuspend(const sigset_t * set) 68105c3a5eaSDavid Xu { 68202c3c858SDavid Xu struct pthread *curthread; 683a091d823SDavid Xu sigset_t newset; 68402c3c858SDavid Xu int ret, old; 685bb535300SJeff Roberson 68602c3c858SDavid Xu curthread = _get_curthread(); 68702c3c858SDavid Xu 68802c3c858SDavid Xu old = curthread->in_sigsuspend; 68902c3c858SDavid Xu curthread->in_sigsuspend = 1; 690f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 69182746ea5SDavid Xu ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); 69202c3c858SDavid Xu _thr_cancel_leave(curthread, 1); 69302c3c858SDavid Xu curthread->in_sigsuspend = old; 69402c3c858SDavid Xu if (curthread->unblock_sigcancel) { 69502c3c858SDavid Xu curthread->unblock_sigcancel = 0; 69602c3c858SDavid Xu SIGEMPTYSET(newset); 69702c3c858SDavid Xu SIGADDSET(newset, SIGCANCEL); 69802c3c858SDavid Xu __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL); 69902c3c858SDavid Xu } 7000ad70ba9SMike Makonnen 701a091d823SDavid Xu return (ret); 702a091d823SDavid Xu } 703a091d823SDavid Xu 704a091d823SDavid Xu int 70505c3a5eaSDavid Xu _sigtimedwait(const sigset_t *set, siginfo_t *info, 70605c3a5eaSDavid Xu const struct timespec * timeout) 70705c3a5eaSDavid Xu { 70805c3a5eaSDavid Xu sigset_t newset; 70905c3a5eaSDavid Xu 71082746ea5SDavid Xu return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 71182746ea5SDavid Xu timeout)); 71205c3a5eaSDavid Xu } 71305c3a5eaSDavid Xu 714635f917aSDavid Xu /* 715635f917aSDavid Xu * Cancellation behavior: 716635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 717635f917aSDavid Xu * it is not canceled. 718635f917aSDavid Xu */ 71905c3a5eaSDavid Xu int 7208495e8b1SKonstantin Belousov __thr_sigtimedwait(const sigset_t *set, siginfo_t *info, 721a091d823SDavid Xu const struct timespec * timeout) 722a091d823SDavid Xu { 723a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 724a091d823SDavid Xu sigset_t newset; 725a091d823SDavid Xu int ret; 726a091d823SDavid Xu 72702c3c858SDavid Xu _thr_cancel_enter(curthread); 72882746ea5SDavid Xu ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 72982746ea5SDavid Xu timeout); 73002c3c858SDavid Xu _thr_cancel_leave(curthread, (ret == -1)); 731a091d823SDavid Xu return (ret); 732a091d823SDavid Xu } 733a091d823SDavid Xu 734a091d823SDavid Xu int 73505c3a5eaSDavid Xu _sigwaitinfo(const sigset_t *set, siginfo_t *info) 73605c3a5eaSDavid Xu { 73705c3a5eaSDavid Xu sigset_t newset; 73805c3a5eaSDavid Xu 73982746ea5SDavid Xu return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info)); 74005c3a5eaSDavid Xu } 74105c3a5eaSDavid Xu 742635f917aSDavid Xu /* 743635f917aSDavid Xu * Cancellation behavior: 744635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 745635f917aSDavid Xu * it is not canceled. 746635f917aSDavid Xu */ 74705c3a5eaSDavid Xu int 7488495e8b1SKonstantin Belousov __thr_sigwaitinfo(const sigset_t *set, siginfo_t *info) 749a091d823SDavid Xu { 750a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 751a091d823SDavid Xu sigset_t newset; 752a091d823SDavid Xu int ret; 753a091d823SDavid Xu 75402c3c858SDavid Xu _thr_cancel_enter(curthread); 75582746ea5SDavid Xu ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info); 75602c3c858SDavid Xu _thr_cancel_leave(curthread, ret == -1); 757a091d823SDavid Xu return (ret); 758a091d823SDavid Xu } 759a091d823SDavid Xu 760a091d823SDavid Xu int 76105c3a5eaSDavid Xu _sigwait(const sigset_t *set, int *sig) 76205c3a5eaSDavid Xu { 76305c3a5eaSDavid Xu sigset_t newset; 76405c3a5eaSDavid Xu 76582746ea5SDavid Xu return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig)); 76605c3a5eaSDavid Xu } 76705c3a5eaSDavid Xu 768635f917aSDavid Xu /* 769635f917aSDavid Xu * Cancellation behavior: 770635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 771635f917aSDavid Xu * it is not canceled. 772635f917aSDavid Xu */ 77305c3a5eaSDavid Xu int 7748495e8b1SKonstantin Belousov __thr_sigwait(const sigset_t *set, int *sig) 775a091d823SDavid Xu { 776a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 777a091d823SDavid Xu sigset_t newset; 778a091d823SDavid Xu int ret; 779a091d823SDavid Xu 78083c9e089SDavid Xu do { 78102c3c858SDavid Xu _thr_cancel_enter(curthread); 78282746ea5SDavid Xu ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig); 78302c3c858SDavid Xu _thr_cancel_leave(curthread, (ret != 0)); 78483c9e089SDavid Xu } while (ret == EINTR); 785a091d823SDavid Xu return (ret); 786bb535300SJeff Roberson } 7875cf22195SDavid Xu 7885cf22195SDavid Xu int 7898495e8b1SKonstantin Belousov __thr_setcontext(const ucontext_t *ucp) 7905cf22195SDavid Xu { 7915cf22195SDavid Xu ucontext_t uc; 7925cf22195SDavid Xu 79366f6c272SDavid Xu if (ucp == NULL) { 79466f6c272SDavid Xu errno = EINVAL; 79566f6c272SDavid Xu return (-1); 79666f6c272SDavid Xu } 797d25183e0SEric van Gyzen if (!SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) 79801618b33SEric van Gyzen return (__sys_setcontext(ucp)); 7995cf22195SDavid Xu (void) memcpy(&uc, ucp, sizeof(uc)); 8008bbeb7e9SDavid Xu SIGDELSET(uc.uc_sigmask, SIGCANCEL); 8018495e8b1SKonstantin Belousov return (__sys_setcontext(&uc)); 8025cf22195SDavid Xu } 8035cf22195SDavid Xu 804acad2b1eSDavid Xu int 8058495e8b1SKonstantin Belousov __thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 806acad2b1eSDavid Xu { 807acad2b1eSDavid Xu ucontext_t uc; 808acad2b1eSDavid Xu 80966f6c272SDavid Xu if (oucp == NULL || ucp == NULL) { 81066f6c272SDavid Xu errno = EINVAL; 81166f6c272SDavid Xu return (-1); 81266f6c272SDavid Xu } 8138bbeb7e9SDavid Xu if (SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) { 814acad2b1eSDavid Xu (void) memcpy(&uc, ucp, sizeof(uc)); 8158bbeb7e9SDavid Xu SIGDELSET(uc.uc_sigmask, SIGCANCEL); 8168bbeb7e9SDavid Xu ucp = &uc; 8178bbeb7e9SDavid Xu } 8188495e8b1SKonstantin Belousov return (__sys_swapcontext(oucp, ucp)); 819acad2b1eSDavid Xu } 820