1bb535300SJeff Roberson /* 2df2cf821SDavid Xu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3bb535300SJeff Roberson * All rights reserved. 4bb535300SJeff Roberson * 5bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 6bb535300SJeff Roberson * modification, are permitted provided that the following conditions 7bb535300SJeff Roberson * are met: 8bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 9df2cf821SDavid Xu * notice unmodified, this list of conditions, and the following 10df2cf821SDavid Xu * disclaimer. 11bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 12bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 13bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 14bb535300SJeff Roberson * 15df2cf821SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16df2cf821SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17df2cf821SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18df2cf821SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19df2cf821SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20df2cf821SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21df2cf821SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22df2cf821SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23df2cf821SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24df2cf821SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25bb535300SJeff Roberson * 26bb535300SJeff Roberson * $FreeBSD$ 27bb535300SJeff Roberson */ 28bb535300SJeff Roberson 2937a6356bSDavid Xu #include "namespace.h" 30bb535300SJeff Roberson #include <sys/param.h> 31bb535300SJeff Roberson #include <sys/types.h> 32bb535300SJeff Roberson #include <sys/signalvar.h> 33bb535300SJeff Roberson #include <signal.h> 34a091d823SDavid Xu #include <errno.h> 35a091d823SDavid Xu #include <string.h> 36bb535300SJeff Roberson #include <pthread.h> 3737a6356bSDavid Xu #include "un-namespace.h" 3802c3c858SDavid Xu #include "libc_private.h" 3989552201SMike Makonnen 40bb535300SJeff Roberson #include "thr_private.h" 41bb535300SJeff Roberson 42bb535300SJeff Roberson /* #define DEBUG_SIGNAL */ 43bb535300SJeff Roberson #ifdef DEBUG_SIGNAL 44bb535300SJeff Roberson #define DBG_MSG stdout_debug 45bb535300SJeff Roberson #else 46bb535300SJeff Roberson #define DBG_MSG(x...) 47bb535300SJeff Roberson #endif 48bb535300SJeff Roberson 4902c3c858SDavid Xu struct usigaction { 5002c3c858SDavid Xu struct sigaction sigact; 5102c3c858SDavid Xu struct urwlock lock; 5202c3c858SDavid Xu }; 5302c3c858SDavid Xu 5402c3c858SDavid Xu static struct usigaction _thr_sigact[_SIG_MAXSIG]; 5502c3c858SDavid Xu 5602c3c858SDavid Xu static void thr_sighandler(int, siginfo_t *, void *); 5702c3c858SDavid Xu static void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *); 5802c3c858SDavid Xu static void check_deferred_signal(struct pthread *); 5902c3c858SDavid Xu static void check_suspend(struct pthread *); 6002c3c858SDavid Xu static void check_cancel(struct pthread *curthread, ucontext_t *ucp); 6102c3c858SDavid Xu 6205c3a5eaSDavid Xu int ___pause(void); 6305c3a5eaSDavid Xu int _raise(int); 6437a6356bSDavid Xu int __sigtimedwait(const sigset_t *set, siginfo_t *info, 6537a6356bSDavid Xu const struct timespec * timeout); 66922d56f9SDavid Xu int _sigtimedwait(const sigset_t *set, siginfo_t *info, 67922d56f9SDavid Xu const struct timespec * timeout); 6837a6356bSDavid Xu int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 69922d56f9SDavid Xu int _sigwaitinfo(const sigset_t *set, siginfo_t *info); 7083c9e089SDavid Xu int ___sigwait(const sigset_t *set, int *sig); 71922d56f9SDavid Xu int _sigwait(const sigset_t *set, int *sig); 72922d56f9SDavid Xu int __sigsuspend(const sigset_t *sigmask); 7302c3c858SDavid Xu int _sigaction(int, const struct sigaction *, struct sigaction *); 745cf22195SDavid Xu int _setcontext(const ucontext_t *); 755cf22195SDavid Xu int _swapcontext(ucontext_t *, const ucontext_t *); 7637a6356bSDavid Xu 7702c3c858SDavid Xu static const sigset_t _thr_deferset={{ 7802c3c858SDavid Xu 0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)| 7902c3c858SDavid Xu _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)), 8002c3c858SDavid Xu 0xffffffff, 8102c3c858SDavid Xu 0xffffffff, 8202c3c858SDavid Xu 0xffffffff}}; 8302c3c858SDavid Xu 8402c3c858SDavid Xu static const sigset_t _thr_maskset={{ 8502c3c858SDavid Xu 0xffffffff, 8602c3c858SDavid Xu 0xffffffff, 8702c3c858SDavid Xu 0xffffffff, 8802c3c858SDavid Xu 0xffffffff}}; 8902c3c858SDavid Xu 9002c3c858SDavid Xu void 9102c3c858SDavid Xu _thr_signal_block(struct pthread *curthread) 9202c3c858SDavid Xu { 9302c3c858SDavid Xu 9402c3c858SDavid Xu if (curthread->sigblock > 0) { 9502c3c858SDavid Xu curthread->sigblock++; 9602c3c858SDavid Xu return; 9702c3c858SDavid Xu } 9802c3c858SDavid Xu __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask); 9902c3c858SDavid Xu curthread->sigblock++; 10002c3c858SDavid Xu } 10102c3c858SDavid Xu 10202c3c858SDavid Xu void 10302c3c858SDavid Xu _thr_signal_unblock(struct pthread *curthread) 10402c3c858SDavid Xu { 10502c3c858SDavid Xu if (--curthread->sigblock == 0) 10602c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 10702c3c858SDavid Xu } 10802c3c858SDavid Xu 10902c3c858SDavid Xu int 11002c3c858SDavid Xu _thr_send_sig(struct pthread *thread, int sig) 11102c3c858SDavid Xu { 11202c3c858SDavid Xu return thr_kill(thread->tid, sig); 11302c3c858SDavid Xu } 11402c3c858SDavid Xu 11502c3c858SDavid Xu static inline void 1165cf22195SDavid Xu remove_thr_signals(sigset_t *set) 1175cf22195SDavid Xu { 1185cf22195SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) 1195cf22195SDavid Xu SIGDELSET(*set, SIGCANCEL); 1205cf22195SDavid Xu } 1215cf22195SDavid Xu 1225cf22195SDavid Xu static const sigset_t * 1235cf22195SDavid Xu thr_remove_thr_signals(const sigset_t *set, sigset_t *newset) 1245cf22195SDavid Xu { 1255cf22195SDavid Xu *newset = *set; 12602c3c858SDavid Xu remove_thr_signals(newset); 12702c3c858SDavid Xu return (newset); 1285cf22195SDavid Xu } 1296fdfcacbSDavid Xu 130a091d823SDavid Xu static void 13137a6356bSDavid Xu sigcancel_handler(int sig __unused, 13202c3c858SDavid Xu siginfo_t *info __unused, ucontext_t *ucp) 133a091d823SDavid Xu { 134a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 13502c3c858SDavid Xu int err; 136a091d823SDavid Xu 13702c3c858SDavid Xu if (THR_IN_CRITICAL(curthread)) 13802c3c858SDavid Xu return; 13902c3c858SDavid Xu err = errno; 14002c3c858SDavid Xu check_suspend(curthread); 14102c3c858SDavid Xu check_cancel(curthread, ucp); 14202c3c858SDavid Xu errno = err; 14302c3c858SDavid Xu } 14402c3c858SDavid Xu 14502c3c858SDavid Xu typedef void (*ohandler)(int sig, int code, 14602c3c858SDavid Xu struct sigcontext *scp, char *addr, __sighandler_t *catcher); 14702c3c858SDavid Xu 14802c3c858SDavid Xu /* 14902c3c858SDavid Xu * The signal handler wrapper is entered with all signal masked. 15002c3c858SDavid Xu */ 15102c3c858SDavid Xu static void 15202c3c858SDavid Xu thr_sighandler(int sig, siginfo_t *info, void *_ucp) 15302c3c858SDavid Xu { 15402c3c858SDavid Xu struct pthread *curthread = _get_curthread(); 15502c3c858SDavid Xu ucontext_t *ucp = _ucp; 15602c3c858SDavid Xu struct sigaction act; 15702c3c858SDavid Xu int err; 15802c3c858SDavid Xu 15902c3c858SDavid Xu err = errno; 16002c3c858SDavid Xu _thr_rwl_rdlock(&_thr_sigact[sig-1].lock); 16102c3c858SDavid Xu act = _thr_sigact[sig-1].sigact; 16202c3c858SDavid Xu _thr_rwl_unlock(&_thr_sigact[sig-1].lock); 16302c3c858SDavid Xu errno = err; 16402c3c858SDavid Xu 16502c3c858SDavid Xu /* 16602c3c858SDavid Xu * if a thread is in critical region, for example it holds low level locks, 16702c3c858SDavid Xu * try to defer the signal processing, however if the signal is synchronous 16802c3c858SDavid Xu * signal, it means a bad thing has happened, this is a programming error, 16902c3c858SDavid Xu * resuming fault point can not help anything (normally causes deadloop), 17002c3c858SDavid Xu * so here we let user code handle it immediately. 17102c3c858SDavid Xu */ 17202c3c858SDavid Xu if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) { 17302c3c858SDavid Xu memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction)); 17402c3c858SDavid Xu memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t)); 17502c3c858SDavid Xu curthread->deferred_sigmask = ucp->uc_sigmask; 17602c3c858SDavid Xu /* mask all signals, we will restore it later. */ 17702c3c858SDavid Xu ucp->uc_sigmask = _thr_deferset; 17802c3c858SDavid Xu return; 17902c3c858SDavid Xu } 18002c3c858SDavid Xu 18102c3c858SDavid Xu handle_signal(&act, sig, info, ucp); 18202c3c858SDavid Xu } 18302c3c858SDavid Xu 18402c3c858SDavid Xu static void 18502c3c858SDavid Xu handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) 18602c3c858SDavid Xu { 18702c3c858SDavid Xu struct pthread *curthread = _get_curthread(); 18802c3c858SDavid Xu ucontext_t uc2; 18902c3c858SDavid Xu __siginfohandler_t *sigfunc; 19002c3c858SDavid Xu int cancel_point; 19102c3c858SDavid Xu int cancel_async; 19202c3c858SDavid Xu int cancel_enable; 19302c3c858SDavid Xu int in_sigsuspend; 19402c3c858SDavid Xu int err; 19502c3c858SDavid Xu 19602c3c858SDavid Xu /* add previous level mask */ 19702c3c858SDavid Xu SIGSETOR(actp->sa_mask, ucp->uc_sigmask); 19802c3c858SDavid Xu 19902c3c858SDavid Xu /* add this signal's mask */ 20002c3c858SDavid Xu if (!(actp->sa_flags & SA_NODEFER)) 20102c3c858SDavid Xu SIGADDSET(actp->sa_mask, sig); 20202c3c858SDavid Xu 20302c3c858SDavid Xu in_sigsuspend = curthread->in_sigsuspend; 20402c3c858SDavid Xu curthread->in_sigsuspend = 0; 20502c3c858SDavid Xu 20602c3c858SDavid Xu /* 20702c3c858SDavid Xu * if thread is in deferred cancellation mode, disable cancellation 20802c3c858SDavid Xu * in signal handler. 20902c3c858SDavid Xu * if user signal handler calls a cancellation point function, e.g, 21002c3c858SDavid Xu * it calls write() to write data to file, because write() is a 21102c3c858SDavid Xu * cancellation point, the thread is immediately cancelled if 21202c3c858SDavid Xu * cancellation is pending, to avoid this problem while thread is in 21302c3c858SDavid Xu * deferring mode, cancellation is temporarily disabled. 21402c3c858SDavid Xu */ 21502c3c858SDavid Xu cancel_point = curthread->cancel_point; 21602c3c858SDavid Xu cancel_async = curthread->cancel_async; 21702c3c858SDavid Xu cancel_enable = curthread->cancel_enable; 21802c3c858SDavid Xu curthread->cancel_point = 0; 21902c3c858SDavid Xu if (!cancel_async) 22002c3c858SDavid Xu curthread->cancel_enable = 0; 22102c3c858SDavid Xu 22202c3c858SDavid Xu /* restore correct mask before calling user handler */ 22302c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL); 22402c3c858SDavid Xu 22502c3c858SDavid Xu sigfunc = actp->sa_sigaction; 22602c3c858SDavid Xu 22702c3c858SDavid Xu /* 22802c3c858SDavid Xu * We have already reset cancellation point flags, so if user's code 22902c3c858SDavid Xu * longjmp()s out of its signal handler, wish its jmpbuf was set 23002c3c858SDavid Xu * outside of a cancellation point, in most cases, this would be 23102c3c858SDavid Xu * true. however, ther is no way to save cancel_enable in jmpbuf, 23202c3c858SDavid Xu * so after setjmps() returns once more, the user code may need to 23302c3c858SDavid Xu * re-set cancel_enable flag by calling pthread_setcancelstate(). 23402c3c858SDavid Xu */ 23502c3c858SDavid Xu if ((actp->sa_flags & SA_SIGINFO) != 0) 23602c3c858SDavid Xu (*(sigfunc))(sig, info, ucp); 23702c3c858SDavid Xu else { 23802c3c858SDavid Xu ((ohandler)(*sigfunc))( 23902c3c858SDavid Xu sig, info->si_code, (struct sigcontext *)ucp, 24002c3c858SDavid Xu info->si_addr, (__sighandler_t *)sigfunc); 24102c3c858SDavid Xu } 24202c3c858SDavid Xu err = errno; 24302c3c858SDavid Xu 24402c3c858SDavid Xu curthread->in_sigsuspend = in_sigsuspend; 24502c3c858SDavid Xu curthread->cancel_point = cancel_point; 24602c3c858SDavid Xu curthread->cancel_enable = cancel_enable; 24702c3c858SDavid Xu 24802c3c858SDavid Xu memcpy(&uc2, ucp, sizeof(uc2)); 24902c3c858SDavid Xu SIGDELSET(uc2.uc_sigmask, SIGCANCEL); 25002c3c858SDavid Xu 25102c3c858SDavid Xu /* reschedule cancellation */ 25202c3c858SDavid Xu check_cancel(curthread, &uc2); 25302c3c858SDavid Xu errno = err; 25402c3c858SDavid Xu __sys_sigreturn(&uc2); 255bc414752SDavid Xu } 256bc414752SDavid Xu 257bc414752SDavid Xu void 258bc414752SDavid Xu _thr_ast(struct pthread *curthread) 259bc414752SDavid Xu { 260635f917aSDavid Xu 26102c3c858SDavid Xu if (!THR_IN_CRITICAL(curthread)) { 26202c3c858SDavid Xu check_deferred_signal(curthread); 26302c3c858SDavid Xu check_suspend(curthread); 26402c3c858SDavid Xu check_cancel(curthread, NULL); 26502c3c858SDavid Xu } 26602c3c858SDavid Xu } 26702c3c858SDavid Xu 26802c3c858SDavid Xu /* reschedule cancellation */ 26902c3c858SDavid Xu static void 27002c3c858SDavid Xu check_cancel(struct pthread *curthread, ucontext_t *ucp) 27102c3c858SDavid Xu { 27202c3c858SDavid Xu 273*81f3e99cSDavid Xu if (__predict_true(!curthread->cancel_pending || 274*81f3e99cSDavid Xu !curthread->cancel_enable || curthread->no_cancel)) 275635f917aSDavid Xu return; 276635f917aSDavid Xu 277635f917aSDavid Xu /* 278635f917aSDavid Xu * Otherwise, we are in defer mode, and we are at 279635f917aSDavid Xu * cancel point, tell kernel to not block the current 280635f917aSDavid Xu * thread on next cancelable system call. 281635f917aSDavid Xu * 28202c3c858SDavid Xu * There are three cases we should call thr_wake() to 28302c3c858SDavid Xu * turn on TDP_WAKEUP or send SIGCANCEL in kernel: 284635f917aSDavid Xu * 1) we are going to call a cancelable system call, 285635f917aSDavid Xu * non-zero cancel_point means we are already in 286635f917aSDavid Xu * cancelable state, next system call is cancelable. 287635f917aSDavid Xu * 2) because _thr_ast() may be called by 288635f917aSDavid Xu * THR_CRITICAL_LEAVE() which is used by rtld rwlock 289635f917aSDavid Xu * and any libthr internal locks, when rtld rwlock 290635f917aSDavid Xu * is used, it is mostly caused my an unresolved PLT. 291635f917aSDavid Xu * those routines may clear the TDP_WAKEUP flag by 292635f917aSDavid Xu * invoking some system calls, in those cases, we 293635f917aSDavid Xu * also should reenable the flag. 29402c3c858SDavid Xu * 3) thread is in sigsuspend(), and the syscall insists 29502c3c858SDavid Xu * on getting a signal before it agrees to return. 296635f917aSDavid Xu */ 297635f917aSDavid Xu if (curthread->cancel_point) { 29802c3c858SDavid Xu if (curthread->in_sigsuspend && ucp) { 29902c3c858SDavid Xu SIGADDSET(ucp->uc_sigmask, SIGCANCEL); 30002c3c858SDavid Xu curthread->unblock_sigcancel = 1; 30102c3c858SDavid Xu _thr_send_sig(curthread, SIGCANCEL); 30202c3c858SDavid Xu } else 303635f917aSDavid Xu thr_wake(curthread->tid); 304*81f3e99cSDavid Xu } else if (curthread->cancel_async) { 305*81f3e99cSDavid Xu /* 306*81f3e99cSDavid Xu * asynchronous cancellation mode, act upon 307*81f3e99cSDavid Xu * immediately. 308*81f3e99cSDavid Xu */ 309*81f3e99cSDavid Xu _pthread_exit_mask(PTHREAD_CANCELED, 310*81f3e99cSDavid Xu ucp? &ucp->uc_sigmask : NULL); 311635f917aSDavid Xu } 312635f917aSDavid Xu } 313635f917aSDavid Xu 31402c3c858SDavid Xu static void 31502c3c858SDavid Xu check_deferred_signal(struct pthread *curthread) 31602c3c858SDavid Xu { 31702c3c858SDavid Xu ucontext_t uc; 31802c3c858SDavid Xu struct sigaction act; 31902c3c858SDavid Xu siginfo_t info; 32002c3c858SDavid Xu volatile int first; 32102c3c858SDavid Xu 32202c3c858SDavid Xu if (__predict_true(curthread->deferred_siginfo.si_signo == 0)) 32302c3c858SDavid Xu return; 32402c3c858SDavid Xu first = 1; 32502c3c858SDavid Xu getcontext(&uc); 32602c3c858SDavid Xu if (first) { 32702c3c858SDavid Xu first = 0; 32802c3c858SDavid Xu act = curthread->deferred_sigact; 32902c3c858SDavid Xu uc.uc_sigmask = curthread->deferred_sigmask; 33002c3c858SDavid Xu memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t)); 33102c3c858SDavid Xu /* remove signal */ 33202c3c858SDavid Xu curthread->deferred_siginfo.si_signo = 0; 33302c3c858SDavid Xu if (act.sa_flags & SA_RESETHAND) { 33402c3c858SDavid Xu struct sigaction tact; 33502c3c858SDavid Xu 33602c3c858SDavid Xu tact = act; 33702c3c858SDavid Xu tact.sa_handler = SIG_DFL; 33802c3c858SDavid Xu _sigaction(info.si_signo, &tact, NULL); 33902c3c858SDavid Xu } 34002c3c858SDavid Xu handle_signal(&act, info.si_signo, &info, &uc); 34102c3c858SDavid Xu } 342a091d823SDavid Xu } 343a091d823SDavid Xu 34402c3c858SDavid Xu static void 34502c3c858SDavid Xu check_suspend(struct pthread *curthread) 346a091d823SDavid Xu { 3478d6a11a0SDavid Xu uint32_t cycle; 34802c3c858SDavid Xu 34902c3c858SDavid Xu if (__predict_true((curthread->flags & 35002c3c858SDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 35102c3c858SDavid Xu != THR_FLAGS_NEED_SUSPEND)) 35202c3c858SDavid Xu return; 353a091d823SDavid Xu 3542ea1f90aSDavid Xu if (curthread->force_exit) 3552ea1f90aSDavid Xu return; 3562ea1f90aSDavid Xu 357bc414752SDavid Xu /* 358bc414752SDavid Xu * Blocks SIGCANCEL which other threads must send. 359bc414752SDavid Xu */ 360a091d823SDavid Xu _thr_signal_block(curthread); 361bc414752SDavid Xu 362bc414752SDavid Xu /* 363bc414752SDavid Xu * Increase critical_count, here we don't use THR_LOCK/UNLOCK 364bc414752SDavid Xu * because we are leaf code, we don't want to recursively call 365bc414752SDavid Xu * ourself. 366bc414752SDavid Xu */ 367bc414752SDavid Xu curthread->critical_count++; 368bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 369bc414752SDavid Xu while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 370bc414752SDavid Xu THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 371bc414752SDavid Xu curthread->cycle++; 372a091d823SDavid Xu cycle = curthread->cycle; 373bc414752SDavid Xu 374bc414752SDavid Xu /* Wake the thread suspending us. */ 3758d6a11a0SDavid Xu _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 376bc414752SDavid Xu 377bc414752SDavid Xu /* 378bc414752SDavid Xu * if we are from pthread_exit, we don't want to 379bc414752SDavid Xu * suspend, just go and die. 380bc414752SDavid Xu */ 381bc414752SDavid Xu if (curthread->state == PS_DEAD) 382bc414752SDavid Xu break; 383bc414752SDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED; 384bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 3858d6a11a0SDavid Xu _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0); 386bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 387a091d823SDavid Xu curthread->flags &= ~THR_FLAGS_SUSPENDED; 388a091d823SDavid Xu } 389bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 390bc414752SDavid Xu curthread->critical_count--; 391bc414752SDavid Xu 392a091d823SDavid Xu _thr_signal_unblock(curthread); 393a091d823SDavid Xu } 394a091d823SDavid Xu 395a091d823SDavid Xu void 396a091d823SDavid Xu _thr_signal_init(void) 397a091d823SDavid Xu { 398a091d823SDavid Xu struct sigaction act; 399a091d823SDavid Xu 40002c3c858SDavid Xu /* Install SIGCANCEL handler. */ 40102c3c858SDavid Xu SIGFILLSET(act.sa_mask); 40202c3c858SDavid Xu act.sa_flags = SA_SIGINFO; 403a091d823SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 404a091d823SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL); 40502c3c858SDavid Xu 40602c3c858SDavid Xu /* Unblock SIGCANCEL */ 40702c3c858SDavid Xu SIGEMPTYSET(act.sa_mask); 40802c3c858SDavid Xu SIGADDSET(act.sa_mask, SIGCANCEL); 40902c3c858SDavid Xu __sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL); 41002c3c858SDavid Xu } 41102c3c858SDavid Xu 41202c3c858SDavid Xu void 41302c3c858SDavid Xu _thr_sigact_unload(struct dl_phdr_info *phdr_info) 41402c3c858SDavid Xu { 415cb4a1047SDavid Xu #if 0 41621a9296fSDavid Xu struct pthread *curthread = _get_curthread(); 41702c3c858SDavid Xu struct urwlock *rwlp; 41802c3c858SDavid Xu struct sigaction *actp; 41902c3c858SDavid Xu struct sigaction kact; 42002c3c858SDavid Xu void (*handler)(int); 42102c3c858SDavid Xu int sig; 42202c3c858SDavid Xu 42321a9296fSDavid Xu _thr_signal_block(curthread); 424cb4a1047SDavid Xu for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 425cb4a1047SDavid Xu actp = &_thr_sigact[sig-1].sigact; 42602c3c858SDavid Xu retry: 42702c3c858SDavid Xu handler = actp->sa_handler; 42802c3c858SDavid Xu if (handler != SIG_DFL && handler != SIG_IGN && 42902c3c858SDavid Xu __elf_phdr_match_addr(phdr_info, handler)) { 430cb4a1047SDavid Xu rwlp = &_thr_sigact[sig-1].lock; 43102c3c858SDavid Xu _thr_rwl_wrlock(rwlp); 43202c3c858SDavid Xu if (handler != actp->sa_handler) { 43302c3c858SDavid Xu _thr_rwl_unlock(rwlp); 43402c3c858SDavid Xu goto retry; 43502c3c858SDavid Xu } 43602c3c858SDavid Xu actp->sa_handler = SIG_DFL; 43702c3c858SDavid Xu actp->sa_flags = SA_SIGINFO; 43802c3c858SDavid Xu SIGEMPTYSET(actp->sa_mask); 43902c3c858SDavid Xu if (__sys_sigaction(sig, NULL, &kact) == 0 && 44002c3c858SDavid Xu kact.sa_handler != SIG_DFL && 44102c3c858SDavid Xu kact.sa_handler != SIG_IGN) 44202c3c858SDavid Xu __sys_sigaction(sig, actp, NULL); 44302c3c858SDavid Xu _thr_rwl_unlock(rwlp); 44402c3c858SDavid Xu } 44502c3c858SDavid Xu } 44621a9296fSDavid Xu _thr_signal_unblock(curthread); 447cb4a1047SDavid Xu #endif 44802c3c858SDavid Xu } 44902c3c858SDavid Xu 45002c3c858SDavid Xu void 45102c3c858SDavid Xu _thr_signal_prefork(void) 45202c3c858SDavid Xu { 45302c3c858SDavid Xu int i; 45402c3c858SDavid Xu 45502c3c858SDavid Xu for (i = 1; i < _SIG_MAXSIG; ++i) 45602c3c858SDavid Xu _thr_rwl_rdlock(&_thr_sigact[i-1].lock); 45702c3c858SDavid Xu } 45802c3c858SDavid Xu 45902c3c858SDavid Xu void 46002c3c858SDavid Xu _thr_signal_postfork(void) 46102c3c858SDavid Xu { 46202c3c858SDavid Xu int i; 46302c3c858SDavid Xu 46402c3c858SDavid Xu for (i = 1; i < _SIG_MAXSIG; ++i) 46502c3c858SDavid Xu _thr_rwl_unlock(&_thr_sigact[i-1].lock); 46602c3c858SDavid Xu } 46702c3c858SDavid Xu 46802c3c858SDavid Xu void 46902c3c858SDavid Xu _thr_signal_postfork_child(void) 47002c3c858SDavid Xu { 47102c3c858SDavid Xu int i; 47202c3c858SDavid Xu 47302c3c858SDavid Xu for (i = 1; i < _SIG_MAXSIG; ++i) 47402c3c858SDavid Xu bzero(&_thr_sigact[i-1].lock, sizeof(struct urwlock)); 475a091d823SDavid Xu } 476a091d823SDavid Xu 477a091d823SDavid Xu void 478a091d823SDavid Xu _thr_signal_deinit(void) 479a091d823SDavid Xu { 480a091d823SDavid Xu } 481a091d823SDavid Xu 48205c3a5eaSDavid Xu __weak_reference(___pause, pause); 48305c3a5eaSDavid Xu 48405c3a5eaSDavid Xu int 48505c3a5eaSDavid Xu ___pause(void) 48605c3a5eaSDavid Xu { 48702c3c858SDavid Xu sigset_t oset; 48805c3a5eaSDavid Xu 48902c3c858SDavid Xu if (_sigprocmask(SIG_BLOCK, NULL, &oset) == -1) 49002c3c858SDavid Xu return (-1); 49102c3c858SDavid Xu return (__sigsuspend(&oset)); 49205c3a5eaSDavid Xu } 49305c3a5eaSDavid Xu 49405c3a5eaSDavid Xu __weak_reference(_raise, raise); 49505c3a5eaSDavid Xu 49605c3a5eaSDavid Xu int 49705c3a5eaSDavid Xu _raise(int sig) 49805c3a5eaSDavid Xu { 49902c3c858SDavid Xu return _thr_send_sig(_get_curthread(), sig); 50005c3a5eaSDavid Xu } 50105c3a5eaSDavid Xu 502a091d823SDavid Xu __weak_reference(_sigaction, sigaction); 503a091d823SDavid Xu 504a091d823SDavid Xu int 505a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 506a091d823SDavid Xu { 50702c3c858SDavid Xu struct sigaction newact, oldact, oldact2; 50802c3c858SDavid Xu sigset_t oldset; 50902c3c858SDavid Xu int ret = 0, err = 0; 51002c3c858SDavid Xu 511b144e48bSKonstantin Belousov if (!_SIG_VALID(sig) || sig == SIGCANCEL) { 512a091d823SDavid Xu errno = EINVAL; 513a091d823SDavid Xu return (-1); 514a091d823SDavid Xu } 515a091d823SDavid Xu 51602c3c858SDavid Xu if (act) 51702c3c858SDavid Xu newact = *act; 51802c3c858SDavid Xu 51902c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 52002c3c858SDavid Xu _thr_rwl_wrlock(&_thr_sigact[sig-1].lock); 52102c3c858SDavid Xu 52202c3c858SDavid Xu if (act != NULL) { 52302c3c858SDavid Xu oldact2 = _thr_sigact[sig-1].sigact; 52402c3c858SDavid Xu 52502c3c858SDavid Xu /* 52602c3c858SDavid Xu * if a new sig handler is SIG_DFL or SIG_IGN, 52702c3c858SDavid Xu * don't remove old handler from _thr_sigact[], 52802c3c858SDavid Xu * so deferred signals still can use the handlers, 52902c3c858SDavid Xu * multiple threads invoking sigaction itself is 53002c3c858SDavid Xu * a race condition, so it is not a problem. 53102c3c858SDavid Xu */ 53202c3c858SDavid Xu if (newact.sa_handler != SIG_DFL && 53302c3c858SDavid Xu newact.sa_handler != SIG_IGN) { 53402c3c858SDavid Xu _thr_sigact[sig-1].sigact = newact; 53502c3c858SDavid Xu remove_thr_signals( 53602c3c858SDavid Xu &_thr_sigact[sig-1].sigact.sa_mask); 53702c3c858SDavid Xu newact.sa_flags &= ~SA_NODEFER; 53802c3c858SDavid Xu newact.sa_flags |= SA_SIGINFO; 53902c3c858SDavid Xu newact.sa_sigaction = thr_sighandler; 54002c3c858SDavid Xu newact.sa_mask = _thr_maskset; /* mask all signals */ 54102c3c858SDavid Xu } 54202c3c858SDavid Xu if ((ret = __sys_sigaction(sig, &newact, &oldact))) { 54302c3c858SDavid Xu err = errno; 54402c3c858SDavid Xu _thr_sigact[sig-1].sigact = oldact2; 54502c3c858SDavid Xu } 54602c3c858SDavid Xu } else if (oact != NULL) { 54702c3c858SDavid Xu ret = __sys_sigaction(sig, NULL, &oldact); 54802c3c858SDavid Xu err = errno; 54902c3c858SDavid Xu } 55002c3c858SDavid Xu 55102c3c858SDavid Xu if (oldact.sa_handler != SIG_DFL && 55202c3c858SDavid Xu oldact.sa_handler != SIG_IGN) { 55302c3c858SDavid Xu oldact = _thr_sigact[sig-1].sigact; 55402c3c858SDavid Xu } 55502c3c858SDavid Xu 55602c3c858SDavid Xu _thr_rwl_unlock(&_thr_sigact[sig-1].lock); 55702c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 55802c3c858SDavid Xu 55902c3c858SDavid Xu if (ret == 0) { 56002c3c858SDavid Xu if (oact != NULL) 56102c3c858SDavid Xu *oact = oldact; 56202c3c858SDavid Xu } else { 56302c3c858SDavid Xu errno = err; 56402c3c858SDavid Xu } 56502c3c858SDavid Xu return (ret); 566a091d823SDavid Xu } 567a091d823SDavid Xu 568a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask); 569a091d823SDavid Xu 570a091d823SDavid Xu int 571a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 572a091d823SDavid Xu { 573a091d823SDavid Xu const sigset_t *p = set; 574a091d823SDavid Xu sigset_t newset; 575a091d823SDavid Xu 576a091d823SDavid Xu if (how != SIG_UNBLOCK) { 577a091d823SDavid Xu if (set != NULL) { 578a091d823SDavid Xu newset = *set; 579a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 580a091d823SDavid Xu p = &newset; 581a091d823SDavid Xu } 582a091d823SDavid Xu } 583a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 584a091d823SDavid Xu } 585a091d823SDavid Xu 586bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask); 587bb535300SJeff Roberson 588bb535300SJeff Roberson int 589bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 590bb535300SJeff Roberson { 591a091d823SDavid Xu if (_sigprocmask(how, set, oset)) 592a091d823SDavid Xu return (errno); 593a091d823SDavid Xu return (0); 594bb535300SJeff Roberson } 595bb535300SJeff Roberson 59605c3a5eaSDavid Xu __weak_reference(__sigsuspend, sigsuspend); 597bb535300SJeff Roberson 598bb535300SJeff Roberson int 599a091d823SDavid Xu _sigsuspend(const sigset_t * set) 600bb535300SJeff Roberson { 60105c3a5eaSDavid Xu sigset_t newset; 60205c3a5eaSDavid Xu 60382746ea5SDavid Xu return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset))); 60405c3a5eaSDavid Xu } 60505c3a5eaSDavid Xu 60605c3a5eaSDavid Xu int 60705c3a5eaSDavid Xu __sigsuspend(const sigset_t * set) 60805c3a5eaSDavid Xu { 60902c3c858SDavid Xu struct pthread *curthread; 610a091d823SDavid Xu sigset_t newset; 61102c3c858SDavid Xu int ret, old; 612bb535300SJeff Roberson 61302c3c858SDavid Xu curthread = _get_curthread(); 61402c3c858SDavid Xu 61502c3c858SDavid Xu old = curthread->in_sigsuspend; 61602c3c858SDavid Xu curthread->in_sigsuspend = 1; 617f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 61882746ea5SDavid Xu ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); 61902c3c858SDavid Xu _thr_cancel_leave(curthread, 1); 62002c3c858SDavid Xu curthread->in_sigsuspend = old; 62102c3c858SDavid Xu if (curthread->unblock_sigcancel) { 62202c3c858SDavid Xu curthread->unblock_sigcancel = 0; 62302c3c858SDavid Xu SIGEMPTYSET(newset); 62402c3c858SDavid Xu SIGADDSET(newset, SIGCANCEL); 62502c3c858SDavid Xu __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL); 62602c3c858SDavid Xu } 6270ad70ba9SMike Makonnen 628a091d823SDavid Xu return (ret); 629a091d823SDavid Xu } 630a091d823SDavid Xu 63183c9e089SDavid Xu __weak_reference(___sigwait, sigwait); 632a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait); 633a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo); 634a091d823SDavid Xu 635a091d823SDavid Xu int 63605c3a5eaSDavid Xu _sigtimedwait(const sigset_t *set, siginfo_t *info, 63705c3a5eaSDavid Xu const struct timespec * timeout) 63805c3a5eaSDavid Xu { 63905c3a5eaSDavid Xu sigset_t newset; 64005c3a5eaSDavid Xu 64182746ea5SDavid Xu return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 64282746ea5SDavid Xu timeout)); 64305c3a5eaSDavid Xu } 64405c3a5eaSDavid Xu 645635f917aSDavid Xu /* 646635f917aSDavid Xu * Cancellation behavior: 647635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 648635f917aSDavid Xu * it is not canceled. 649635f917aSDavid Xu */ 65005c3a5eaSDavid Xu int 651a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info, 652a091d823SDavid Xu const struct timespec * timeout) 653a091d823SDavid Xu { 654a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 655a091d823SDavid Xu sigset_t newset; 656a091d823SDavid Xu int ret; 657a091d823SDavid Xu 65802c3c858SDavid Xu _thr_cancel_enter(curthread); 65982746ea5SDavid Xu ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 66082746ea5SDavid Xu timeout); 66102c3c858SDavid Xu _thr_cancel_leave(curthread, (ret == -1)); 662a091d823SDavid Xu return (ret); 663a091d823SDavid Xu } 664a091d823SDavid Xu 665a091d823SDavid Xu int 66605c3a5eaSDavid Xu _sigwaitinfo(const sigset_t *set, siginfo_t *info) 66705c3a5eaSDavid Xu { 66805c3a5eaSDavid Xu sigset_t newset; 66905c3a5eaSDavid Xu 67082746ea5SDavid Xu return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info)); 67105c3a5eaSDavid Xu } 67205c3a5eaSDavid Xu 673635f917aSDavid Xu /* 674635f917aSDavid Xu * Cancellation behavior: 675635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 676635f917aSDavid Xu * it is not canceled. 677635f917aSDavid Xu */ 67805c3a5eaSDavid Xu int 679a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info) 680a091d823SDavid Xu { 681a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 682a091d823SDavid Xu sigset_t newset; 683a091d823SDavid Xu int ret; 684a091d823SDavid Xu 68502c3c858SDavid Xu _thr_cancel_enter(curthread); 68682746ea5SDavid Xu ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info); 68702c3c858SDavid Xu _thr_cancel_leave(curthread, ret == -1); 688a091d823SDavid Xu return (ret); 689a091d823SDavid Xu } 690a091d823SDavid Xu 691a091d823SDavid Xu int 69205c3a5eaSDavid Xu _sigwait(const sigset_t *set, int *sig) 69305c3a5eaSDavid Xu { 69405c3a5eaSDavid Xu sigset_t newset; 69505c3a5eaSDavid Xu 69682746ea5SDavid Xu return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig)); 69705c3a5eaSDavid Xu } 69805c3a5eaSDavid Xu 699635f917aSDavid Xu /* 700635f917aSDavid Xu * Cancellation behavior: 701635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 702635f917aSDavid Xu * it is not canceled. 703635f917aSDavid Xu */ 70405c3a5eaSDavid Xu int 70583c9e089SDavid Xu ___sigwait(const sigset_t *set, int *sig) 706a091d823SDavid Xu { 707a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 708a091d823SDavid Xu sigset_t newset; 709a091d823SDavid Xu int ret; 710a091d823SDavid Xu 71183c9e089SDavid Xu do { 71202c3c858SDavid Xu _thr_cancel_enter(curthread); 71382746ea5SDavid Xu ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig); 71402c3c858SDavid Xu _thr_cancel_leave(curthread, (ret != 0)); 71583c9e089SDavid Xu } while (ret == EINTR); 716a091d823SDavid Xu return (ret); 717bb535300SJeff Roberson } 7185cf22195SDavid Xu 7195cf22195SDavid Xu __weak_reference(_setcontext, setcontext); 7205cf22195SDavid Xu int 7215cf22195SDavid Xu _setcontext(const ucontext_t *ucp) 7225cf22195SDavid Xu { 7235cf22195SDavid Xu ucontext_t uc; 7245cf22195SDavid Xu 7255cf22195SDavid Xu (void) memcpy(&uc, ucp, sizeof(uc)); 7265cf22195SDavid Xu remove_thr_signals(&uc.uc_sigmask); 7275cf22195SDavid Xu return __sys_setcontext(&uc); 7285cf22195SDavid Xu } 7295cf22195SDavid Xu 7305cf22195SDavid Xu __weak_reference(_swapcontext, swapcontext); 7315cf22195SDavid Xu int 7325cf22195SDavid Xu _swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 7335cf22195SDavid Xu { 7345cf22195SDavid Xu ucontext_t uc; 7355cf22195SDavid Xu 7365cf22195SDavid Xu (void) memcpy(&uc, ucp, sizeof(uc)); 7375cf22195SDavid Xu remove_thr_signals(&uc.uc_sigmask); 7385cf22195SDavid Xu return __sys_swapcontext(oucp, &uc); 7395cf22195SDavid Xu } 740