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> 3510280ca6SKonstantin Belousov #include <stdlib.h> 36a091d823SDavid Xu #include <string.h> 37bb535300SJeff Roberson #include <pthread.h> 3837a6356bSDavid Xu #include "un-namespace.h" 3902c3c858SDavid Xu #include "libc_private.h" 4089552201SMike Makonnen 41bb535300SJeff Roberson #include "thr_private.h" 42bb535300SJeff Roberson 43bb535300SJeff Roberson /* #define DEBUG_SIGNAL */ 44bb535300SJeff Roberson #ifdef DEBUG_SIGNAL 45bb535300SJeff Roberson #define DBG_MSG stdout_debug 46bb535300SJeff Roberson #else 47bb535300SJeff Roberson #define DBG_MSG(x...) 48bb535300SJeff Roberson #endif 49bb535300SJeff Roberson 5002c3c858SDavid Xu struct usigaction { 5102c3c858SDavid Xu struct sigaction sigact; 5202c3c858SDavid Xu struct urwlock lock; 5302c3c858SDavid Xu }; 5402c3c858SDavid Xu 5502c3c858SDavid Xu static struct usigaction _thr_sigact[_SIG_MAXSIG]; 5602c3c858SDavid Xu 5702c3c858SDavid Xu static void thr_sighandler(int, siginfo_t *, void *); 5802c3c858SDavid Xu static void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *); 5902c3c858SDavid Xu static void check_deferred_signal(struct pthread *); 6002c3c858SDavid Xu static void check_suspend(struct pthread *); 6102c3c858SDavid Xu static void check_cancel(struct pthread *curthread, ucontext_t *ucp); 6202c3c858SDavid Xu 6305c3a5eaSDavid Xu int ___pause(void); 6405c3a5eaSDavid Xu int _raise(int); 6537a6356bSDavid Xu int __sigtimedwait(const sigset_t *set, siginfo_t *info, 6637a6356bSDavid Xu const struct timespec * timeout); 67922d56f9SDavid Xu int _sigtimedwait(const sigset_t *set, siginfo_t *info, 68922d56f9SDavid Xu const struct timespec * timeout); 6937a6356bSDavid Xu int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 70922d56f9SDavid Xu int _sigwaitinfo(const sigset_t *set, siginfo_t *info); 7183c9e089SDavid Xu int ___sigwait(const sigset_t *set, int *sig); 72922d56f9SDavid Xu int _sigwait(const sigset_t *set, int *sig); 73922d56f9SDavid Xu int __sigsuspend(const sigset_t *sigmask); 7402c3c858SDavid Xu int _sigaction(int, const struct sigaction *, struct sigaction *); 755cf22195SDavid Xu int _setcontext(const ucontext_t *); 765cf22195SDavid Xu int _swapcontext(ucontext_t *, const ucontext_t *); 7737a6356bSDavid Xu 7802c3c858SDavid Xu static const sigset_t _thr_deferset={{ 7902c3c858SDavid Xu 0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)| 8002c3c858SDavid Xu _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)), 8102c3c858SDavid Xu 0xffffffff, 8202c3c858SDavid Xu 0xffffffff, 8302c3c858SDavid Xu 0xffffffff}}; 8402c3c858SDavid Xu 8502c3c858SDavid Xu static const sigset_t _thr_maskset={{ 8602c3c858SDavid Xu 0xffffffff, 8702c3c858SDavid Xu 0xffffffff, 8802c3c858SDavid Xu 0xffffffff, 8902c3c858SDavid Xu 0xffffffff}}; 9002c3c858SDavid Xu 9102c3c858SDavid Xu void 9202c3c858SDavid Xu _thr_signal_block(struct pthread *curthread) 9302c3c858SDavid Xu { 9402c3c858SDavid Xu 9502c3c858SDavid Xu if (curthread->sigblock > 0) { 9602c3c858SDavid Xu curthread->sigblock++; 9702c3c858SDavid Xu return; 9802c3c858SDavid Xu } 9902c3c858SDavid Xu __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask); 10002c3c858SDavid Xu curthread->sigblock++; 10102c3c858SDavid Xu } 10202c3c858SDavid Xu 10302c3c858SDavid Xu void 10402c3c858SDavid Xu _thr_signal_unblock(struct pthread *curthread) 10502c3c858SDavid Xu { 10602c3c858SDavid Xu if (--curthread->sigblock == 0) 10702c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 10802c3c858SDavid Xu } 10902c3c858SDavid Xu 11002c3c858SDavid Xu int 11102c3c858SDavid Xu _thr_send_sig(struct pthread *thread, int sig) 11202c3c858SDavid Xu { 11302c3c858SDavid Xu return thr_kill(thread->tid, sig); 11402c3c858SDavid Xu } 11502c3c858SDavid Xu 11602c3c858SDavid Xu static inline void 1175cf22195SDavid Xu remove_thr_signals(sigset_t *set) 1185cf22195SDavid Xu { 1195cf22195SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) 1205cf22195SDavid Xu SIGDELSET(*set, SIGCANCEL); 1215cf22195SDavid Xu } 1225cf22195SDavid Xu 1235cf22195SDavid Xu static const sigset_t * 1245cf22195SDavid Xu thr_remove_thr_signals(const sigset_t *set, sigset_t *newset) 1255cf22195SDavid Xu { 1265cf22195SDavid Xu *newset = *set; 12702c3c858SDavid Xu remove_thr_signals(newset); 12802c3c858SDavid Xu return (newset); 1295cf22195SDavid Xu } 1306fdfcacbSDavid Xu 131a091d823SDavid Xu static void 13237a6356bSDavid Xu sigcancel_handler(int sig __unused, 13302c3c858SDavid Xu siginfo_t *info __unused, ucontext_t *ucp) 134a091d823SDavid Xu { 135a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 13602c3c858SDavid Xu int err; 137a091d823SDavid Xu 13802c3c858SDavid Xu if (THR_IN_CRITICAL(curthread)) 13902c3c858SDavid Xu return; 14002c3c858SDavid Xu err = errno; 14102c3c858SDavid Xu check_suspend(curthread); 14202c3c858SDavid Xu check_cancel(curthread, ucp); 14302c3c858SDavid Xu errno = err; 14402c3c858SDavid Xu } 14502c3c858SDavid Xu 14602c3c858SDavid Xu typedef void (*ohandler)(int sig, int code, 14702c3c858SDavid Xu struct sigcontext *scp, char *addr, __sighandler_t *catcher); 14802c3c858SDavid Xu 14902c3c858SDavid Xu /* 15002c3c858SDavid Xu * The signal handler wrapper is entered with all signal masked. 15102c3c858SDavid Xu */ 15202c3c858SDavid Xu static void 15302c3c858SDavid Xu thr_sighandler(int sig, siginfo_t *info, void *_ucp) 15402c3c858SDavid Xu { 15502c3c858SDavid Xu struct pthread *curthread = _get_curthread(); 15602c3c858SDavid Xu ucontext_t *ucp = _ucp; 15702c3c858SDavid Xu struct sigaction act; 15802c3c858SDavid Xu int err; 15902c3c858SDavid Xu 16002c3c858SDavid Xu err = errno; 16102c3c858SDavid Xu _thr_rwl_rdlock(&_thr_sigact[sig-1].lock); 16202c3c858SDavid Xu act = _thr_sigact[sig-1].sigact; 16302c3c858SDavid Xu _thr_rwl_unlock(&_thr_sigact[sig-1].lock); 16402c3c858SDavid Xu errno = err; 16502c3c858SDavid Xu 16602c3c858SDavid Xu /* 16702c3c858SDavid Xu * if a thread is in critical region, for example it holds low level locks, 16802c3c858SDavid Xu * try to defer the signal processing, however if the signal is synchronous 16902c3c858SDavid Xu * signal, it means a bad thing has happened, this is a programming error, 17002c3c858SDavid Xu * resuming fault point can not help anything (normally causes deadloop), 17102c3c858SDavid Xu * so here we let user code handle it immediately. 17202c3c858SDavid Xu */ 17302c3c858SDavid Xu if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) { 17402c3c858SDavid Xu memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction)); 17502c3c858SDavid Xu memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t)); 17602c3c858SDavid Xu curthread->deferred_sigmask = ucp->uc_sigmask; 17702c3c858SDavid Xu /* mask all signals, we will restore it later. */ 17802c3c858SDavid Xu ucp->uc_sigmask = _thr_deferset; 17902c3c858SDavid Xu return; 18002c3c858SDavid Xu } 18102c3c858SDavid Xu 18202c3c858SDavid Xu handle_signal(&act, sig, info, ucp); 18302c3c858SDavid Xu } 18402c3c858SDavid Xu 18502c3c858SDavid Xu static void 18602c3c858SDavid Xu handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) 18702c3c858SDavid Xu { 18802c3c858SDavid Xu struct pthread *curthread = _get_curthread(); 18902c3c858SDavid Xu ucontext_t uc2; 19002c3c858SDavid Xu __siginfohandler_t *sigfunc; 19102c3c858SDavid Xu int cancel_point; 19202c3c858SDavid Xu int cancel_async; 19302c3c858SDavid Xu int cancel_enable; 19402c3c858SDavid Xu int in_sigsuspend; 19502c3c858SDavid Xu int err; 19602c3c858SDavid Xu 19702c3c858SDavid Xu /* add previous level mask */ 19802c3c858SDavid Xu SIGSETOR(actp->sa_mask, ucp->uc_sigmask); 19902c3c858SDavid Xu 20002c3c858SDavid Xu /* add this signal's mask */ 20102c3c858SDavid Xu if (!(actp->sa_flags & SA_NODEFER)) 20202c3c858SDavid Xu SIGADDSET(actp->sa_mask, sig); 20302c3c858SDavid Xu 20402c3c858SDavid Xu in_sigsuspend = curthread->in_sigsuspend; 20502c3c858SDavid Xu curthread->in_sigsuspend = 0; 20602c3c858SDavid Xu 20702c3c858SDavid Xu /* 208*5b1dd970SKonstantin Belousov * If thread is in deferred cancellation mode, disable cancellation 20902c3c858SDavid Xu * in signal handler. 210*5b1dd970SKonstantin Belousov * If user signal handler calls a cancellation point function, e.g, 21102c3c858SDavid Xu * it calls write() to write data to file, because write() is a 21202c3c858SDavid Xu * cancellation point, the thread is immediately cancelled if 21302c3c858SDavid Xu * cancellation is pending, to avoid this problem while thread is in 21402c3c858SDavid Xu * deferring mode, cancellation is temporarily disabled. 21502c3c858SDavid Xu */ 21602c3c858SDavid Xu cancel_point = curthread->cancel_point; 21702c3c858SDavid Xu cancel_async = curthread->cancel_async; 21802c3c858SDavid Xu cancel_enable = curthread->cancel_enable; 21902c3c858SDavid Xu curthread->cancel_point = 0; 22002c3c858SDavid Xu if (!cancel_async) 22102c3c858SDavid Xu curthread->cancel_enable = 0; 22202c3c858SDavid Xu 22302c3c858SDavid Xu /* restore correct mask before calling user handler */ 22402c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL); 22502c3c858SDavid Xu 22602c3c858SDavid Xu sigfunc = actp->sa_sigaction; 22702c3c858SDavid Xu 22802c3c858SDavid Xu /* 22902c3c858SDavid Xu * We have already reset cancellation point flags, so if user's code 23002c3c858SDavid Xu * longjmp()s out of its signal handler, wish its jmpbuf was set 23102c3c858SDavid Xu * outside of a cancellation point, in most cases, this would be 232*5b1dd970SKonstantin Belousov * true. However, there is no way to save cancel_enable in jmpbuf, 23302c3c858SDavid Xu * so after setjmps() returns once more, the user code may need to 23402c3c858SDavid Xu * re-set cancel_enable flag by calling pthread_setcancelstate(). 23502c3c858SDavid Xu */ 23602c3c858SDavid Xu if ((actp->sa_flags & SA_SIGINFO) != 0) 23702c3c858SDavid Xu (*(sigfunc))(sig, info, ucp); 23802c3c858SDavid Xu else { 23902c3c858SDavid Xu ((ohandler)(*sigfunc))( 24002c3c858SDavid Xu sig, info->si_code, (struct sigcontext *)ucp, 24102c3c858SDavid Xu info->si_addr, (__sighandler_t *)sigfunc); 24202c3c858SDavid Xu } 24302c3c858SDavid Xu err = errno; 24402c3c858SDavid Xu 24502c3c858SDavid Xu curthread->in_sigsuspend = in_sigsuspend; 24602c3c858SDavid Xu curthread->cancel_point = cancel_point; 24702c3c858SDavid Xu curthread->cancel_enable = cancel_enable; 24802c3c858SDavid Xu 24902c3c858SDavid Xu memcpy(&uc2, ucp, sizeof(uc2)); 25002c3c858SDavid Xu SIGDELSET(uc2.uc_sigmask, SIGCANCEL); 25102c3c858SDavid Xu 25202c3c858SDavid Xu /* reschedule cancellation */ 25302c3c858SDavid Xu check_cancel(curthread, &uc2); 25402c3c858SDavid Xu errno = err; 25502c3c858SDavid Xu __sys_sigreturn(&uc2); 256bc414752SDavid Xu } 257bc414752SDavid Xu 258bc414752SDavid Xu void 259bc414752SDavid Xu _thr_ast(struct pthread *curthread) 260bc414752SDavid Xu { 261635f917aSDavid Xu 26202c3c858SDavid Xu if (!THR_IN_CRITICAL(curthread)) { 26302c3c858SDavid Xu check_deferred_signal(curthread); 26402c3c858SDavid Xu check_suspend(curthread); 26502c3c858SDavid Xu check_cancel(curthread, NULL); 26602c3c858SDavid Xu } 26702c3c858SDavid Xu } 26802c3c858SDavid Xu 26902c3c858SDavid Xu /* reschedule cancellation */ 27002c3c858SDavid Xu static void 27102c3c858SDavid Xu check_cancel(struct pthread *curthread, ucontext_t *ucp) 27202c3c858SDavid Xu { 27302c3c858SDavid Xu 27481f3e99cSDavid Xu if (__predict_true(!curthread->cancel_pending || 27581f3e99cSDavid Xu !curthread->cancel_enable || curthread->no_cancel)) 276635f917aSDavid Xu return; 277635f917aSDavid Xu 278635f917aSDavid Xu /* 279635f917aSDavid Xu * Otherwise, we are in defer mode, and we are at 280635f917aSDavid Xu * cancel point, tell kernel to not block the current 281635f917aSDavid Xu * thread on next cancelable system call. 282635f917aSDavid Xu * 28302c3c858SDavid Xu * There are three cases we should call thr_wake() to 28402c3c858SDavid Xu * turn on TDP_WAKEUP or send SIGCANCEL in kernel: 285635f917aSDavid Xu * 1) we are going to call a cancelable system call, 286635f917aSDavid Xu * non-zero cancel_point means we are already in 287635f917aSDavid Xu * cancelable state, next system call is cancelable. 288635f917aSDavid Xu * 2) because _thr_ast() may be called by 289635f917aSDavid Xu * THR_CRITICAL_LEAVE() which is used by rtld rwlock 290635f917aSDavid Xu * and any libthr internal locks, when rtld rwlock 291635f917aSDavid Xu * is used, it is mostly caused my an unresolved PLT. 292635f917aSDavid Xu * those routines may clear the TDP_WAKEUP flag by 293635f917aSDavid Xu * invoking some system calls, in those cases, we 294635f917aSDavid Xu * also should reenable the flag. 29502c3c858SDavid Xu * 3) thread is in sigsuspend(), and the syscall insists 29602c3c858SDavid Xu * on getting a signal before it agrees to return. 297635f917aSDavid Xu */ 298635f917aSDavid Xu if (curthread->cancel_point) { 29902c3c858SDavid Xu if (curthread->in_sigsuspend && ucp) { 30002c3c858SDavid Xu SIGADDSET(ucp->uc_sigmask, SIGCANCEL); 30102c3c858SDavid Xu curthread->unblock_sigcancel = 1; 30202c3c858SDavid Xu _thr_send_sig(curthread, SIGCANCEL); 30302c3c858SDavid Xu } else 304635f917aSDavid Xu thr_wake(curthread->tid); 30581f3e99cSDavid Xu } else if (curthread->cancel_async) { 30681f3e99cSDavid Xu /* 30781f3e99cSDavid Xu * asynchronous cancellation mode, act upon 30881f3e99cSDavid Xu * immediately. 30981f3e99cSDavid Xu */ 31081f3e99cSDavid Xu _pthread_exit_mask(PTHREAD_CANCELED, 31181f3e99cSDavid Xu ucp? &ucp->uc_sigmask : NULL); 312635f917aSDavid Xu } 313635f917aSDavid Xu } 314635f917aSDavid Xu 31502c3c858SDavid Xu static void 31602c3c858SDavid Xu check_deferred_signal(struct pthread *curthread) 31702c3c858SDavid Xu { 31810280ca6SKonstantin Belousov ucontext_t *uc; 31902c3c858SDavid Xu struct sigaction act; 32002c3c858SDavid Xu siginfo_t info; 32102c3c858SDavid Xu 32202c3c858SDavid Xu if (__predict_true(curthread->deferred_siginfo.si_signo == 0)) 32302c3c858SDavid Xu return; 32410280ca6SKonstantin Belousov 32510280ca6SKonstantin Belousov #if defined(__amd64__) || defined(__i386__) 32610280ca6SKonstantin Belousov uc = alloca(__getcontextx_size()); 32710280ca6SKonstantin Belousov __fillcontextx((char *)uc); 32810280ca6SKonstantin Belousov #else 32910280ca6SKonstantin Belousov ucontext_t ucv; 33010280ca6SKonstantin Belousov uc = &ucv; 33110280ca6SKonstantin Belousov getcontext(uc); 33210280ca6SKonstantin Belousov #endif 33365a6aaf1SDavid Xu if (curthread->deferred_siginfo.si_signo != 0) { 33402c3c858SDavid Xu act = curthread->deferred_sigact; 33510280ca6SKonstantin Belousov uc->uc_sigmask = curthread->deferred_sigmask; 33602c3c858SDavid Xu memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t)); 33702c3c858SDavid Xu /* remove signal */ 33802c3c858SDavid Xu curthread->deferred_siginfo.si_signo = 0; 33910280ca6SKonstantin Belousov handle_signal(&act, info.si_signo, &info, uc); 34002c3c858SDavid Xu } 341a091d823SDavid Xu } 342a091d823SDavid Xu 34302c3c858SDavid Xu static void 34402c3c858SDavid Xu check_suspend(struct pthread *curthread) 345a091d823SDavid Xu { 3468d6a11a0SDavid Xu uint32_t cycle; 34702c3c858SDavid Xu 34802c3c858SDavid Xu if (__predict_true((curthread->flags & 34902c3c858SDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 35002c3c858SDavid Xu != THR_FLAGS_NEED_SUSPEND)) 35102c3c858SDavid Xu return; 352a7b84c65SDavid Xu if (curthread == _single_thread) 353a7b84c65SDavid Xu return; 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 45591792417SJilles Tjoelker 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 46491792417SJilles Tjoelker 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 47391792417SJilles Tjoelker 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) { 5536ed79f06SDavid Xu if (act != NULL) 5546ed79f06SDavid Xu oldact = oldact2; 5556ed79f06SDavid Xu else if (oact != NULL) 55602c3c858SDavid Xu oldact = _thr_sigact[sig-1].sigact; 55702c3c858SDavid Xu } 55802c3c858SDavid Xu 55902c3c858SDavid Xu _thr_rwl_unlock(&_thr_sigact[sig-1].lock); 56002c3c858SDavid Xu __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 56102c3c858SDavid Xu 56202c3c858SDavid Xu if (ret == 0) { 56302c3c858SDavid Xu if (oact != NULL) 56402c3c858SDavid Xu *oact = oldact; 56502c3c858SDavid Xu } else { 56602c3c858SDavid Xu errno = err; 56702c3c858SDavid Xu } 56802c3c858SDavid Xu return (ret); 569a091d823SDavid Xu } 570a091d823SDavid Xu 571a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask); 572a091d823SDavid Xu 573a091d823SDavid Xu int 574a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 575a091d823SDavid Xu { 576a091d823SDavid Xu const sigset_t *p = set; 577a091d823SDavid Xu sigset_t newset; 578a091d823SDavid Xu 579a091d823SDavid Xu if (how != SIG_UNBLOCK) { 580a091d823SDavid Xu if (set != NULL) { 581a091d823SDavid Xu newset = *set; 582a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 583a091d823SDavid Xu p = &newset; 584a091d823SDavid Xu } 585a091d823SDavid Xu } 586a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 587a091d823SDavid Xu } 588a091d823SDavid Xu 589bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask); 590bb535300SJeff Roberson 591bb535300SJeff Roberson int 592bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 593bb535300SJeff Roberson { 594a091d823SDavid Xu if (_sigprocmask(how, set, oset)) 595a091d823SDavid Xu return (errno); 596a091d823SDavid Xu return (0); 597bb535300SJeff Roberson } 598bb535300SJeff Roberson 59905c3a5eaSDavid Xu __weak_reference(__sigsuspend, sigsuspend); 600bb535300SJeff Roberson 601bb535300SJeff Roberson int 602a091d823SDavid Xu _sigsuspend(const sigset_t * set) 603bb535300SJeff Roberson { 60405c3a5eaSDavid Xu sigset_t newset; 60505c3a5eaSDavid Xu 60682746ea5SDavid Xu return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset))); 60705c3a5eaSDavid Xu } 60805c3a5eaSDavid Xu 60905c3a5eaSDavid Xu int 61005c3a5eaSDavid Xu __sigsuspend(const sigset_t * set) 61105c3a5eaSDavid Xu { 61202c3c858SDavid Xu struct pthread *curthread; 613a091d823SDavid Xu sigset_t newset; 61402c3c858SDavid Xu int ret, old; 615bb535300SJeff Roberson 61602c3c858SDavid Xu curthread = _get_curthread(); 61702c3c858SDavid Xu 61802c3c858SDavid Xu old = curthread->in_sigsuspend; 61902c3c858SDavid Xu curthread->in_sigsuspend = 1; 620f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 62182746ea5SDavid Xu ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); 62202c3c858SDavid Xu _thr_cancel_leave(curthread, 1); 62302c3c858SDavid Xu curthread->in_sigsuspend = old; 62402c3c858SDavid Xu if (curthread->unblock_sigcancel) { 62502c3c858SDavid Xu curthread->unblock_sigcancel = 0; 62602c3c858SDavid Xu SIGEMPTYSET(newset); 62702c3c858SDavid Xu SIGADDSET(newset, SIGCANCEL); 62802c3c858SDavid Xu __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL); 62902c3c858SDavid Xu } 6300ad70ba9SMike Makonnen 631a091d823SDavid Xu return (ret); 632a091d823SDavid Xu } 633a091d823SDavid Xu 63483c9e089SDavid Xu __weak_reference(___sigwait, sigwait); 635a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait); 636a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo); 637a091d823SDavid Xu 638a091d823SDavid Xu int 63905c3a5eaSDavid Xu _sigtimedwait(const sigset_t *set, siginfo_t *info, 64005c3a5eaSDavid Xu const struct timespec * timeout) 64105c3a5eaSDavid Xu { 64205c3a5eaSDavid Xu sigset_t newset; 64305c3a5eaSDavid Xu 64482746ea5SDavid Xu return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 64582746ea5SDavid Xu timeout)); 64605c3a5eaSDavid Xu } 64705c3a5eaSDavid Xu 648635f917aSDavid Xu /* 649635f917aSDavid Xu * Cancellation behavior: 650635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 651635f917aSDavid Xu * it is not canceled. 652635f917aSDavid Xu */ 65305c3a5eaSDavid Xu int 654a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info, 655a091d823SDavid Xu const struct timespec * timeout) 656a091d823SDavid Xu { 657a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 658a091d823SDavid Xu sigset_t newset; 659a091d823SDavid Xu int ret; 660a091d823SDavid Xu 66102c3c858SDavid Xu _thr_cancel_enter(curthread); 66282746ea5SDavid Xu ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 66382746ea5SDavid Xu timeout); 66402c3c858SDavid Xu _thr_cancel_leave(curthread, (ret == -1)); 665a091d823SDavid Xu return (ret); 666a091d823SDavid Xu } 667a091d823SDavid Xu 668a091d823SDavid Xu int 66905c3a5eaSDavid Xu _sigwaitinfo(const sigset_t *set, siginfo_t *info) 67005c3a5eaSDavid Xu { 67105c3a5eaSDavid Xu sigset_t newset; 67205c3a5eaSDavid Xu 67382746ea5SDavid Xu return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info)); 67405c3a5eaSDavid Xu } 67505c3a5eaSDavid Xu 676635f917aSDavid Xu /* 677635f917aSDavid Xu * Cancellation behavior: 678635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 679635f917aSDavid Xu * it is not canceled. 680635f917aSDavid Xu */ 68105c3a5eaSDavid Xu int 682a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info) 683a091d823SDavid Xu { 684a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 685a091d823SDavid Xu sigset_t newset; 686a091d823SDavid Xu int ret; 687a091d823SDavid Xu 68802c3c858SDavid Xu _thr_cancel_enter(curthread); 68982746ea5SDavid Xu ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info); 69002c3c858SDavid Xu _thr_cancel_leave(curthread, ret == -1); 691a091d823SDavid Xu return (ret); 692a091d823SDavid Xu } 693a091d823SDavid Xu 694a091d823SDavid Xu int 69505c3a5eaSDavid Xu _sigwait(const sigset_t *set, int *sig) 69605c3a5eaSDavid Xu { 69705c3a5eaSDavid Xu sigset_t newset; 69805c3a5eaSDavid Xu 69982746ea5SDavid Xu return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig)); 70005c3a5eaSDavid Xu } 70105c3a5eaSDavid Xu 702635f917aSDavid Xu /* 703635f917aSDavid Xu * Cancellation behavior: 704635f917aSDavid Xu * Thread may be canceled at start, if thread got signal, 705635f917aSDavid Xu * it is not canceled. 706635f917aSDavid Xu */ 70705c3a5eaSDavid Xu int 70883c9e089SDavid Xu ___sigwait(const sigset_t *set, int *sig) 709a091d823SDavid Xu { 710a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 711a091d823SDavid Xu sigset_t newset; 712a091d823SDavid Xu int ret; 713a091d823SDavid Xu 71483c9e089SDavid Xu do { 71502c3c858SDavid Xu _thr_cancel_enter(curthread); 71682746ea5SDavid Xu ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig); 71702c3c858SDavid Xu _thr_cancel_leave(curthread, (ret != 0)); 71883c9e089SDavid Xu } while (ret == EINTR); 719a091d823SDavid Xu return (ret); 720bb535300SJeff Roberson } 7215cf22195SDavid Xu 7225cf22195SDavid Xu __weak_reference(_setcontext, setcontext); 7235cf22195SDavid Xu int 7245cf22195SDavid Xu _setcontext(const ucontext_t *ucp) 7255cf22195SDavid Xu { 7265cf22195SDavid Xu ucontext_t uc; 7275cf22195SDavid Xu 72866f6c272SDavid Xu if (ucp == NULL) { 72966f6c272SDavid Xu errno = EINVAL; 73066f6c272SDavid Xu return (-1); 73166f6c272SDavid Xu } 7328bbeb7e9SDavid Xu if (!SIGISMEMBER(uc.uc_sigmask, SIGCANCEL)) 7338bbeb7e9SDavid Xu return __sys_setcontext(ucp); 7345cf22195SDavid Xu (void) memcpy(&uc, ucp, sizeof(uc)); 7358bbeb7e9SDavid Xu SIGDELSET(uc.uc_sigmask, SIGCANCEL); 7365cf22195SDavid Xu return __sys_setcontext(&uc); 7375cf22195SDavid Xu } 7385cf22195SDavid Xu 739acad2b1eSDavid Xu __weak_reference(_swapcontext, swapcontext); 740acad2b1eSDavid Xu int 741acad2b1eSDavid Xu _swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 742acad2b1eSDavid Xu { 743acad2b1eSDavid Xu ucontext_t uc; 744acad2b1eSDavid Xu 74566f6c272SDavid Xu if (oucp == NULL || ucp == NULL) { 74666f6c272SDavid Xu errno = EINVAL; 74766f6c272SDavid Xu return (-1); 74866f6c272SDavid Xu } 7498bbeb7e9SDavid Xu if (SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) { 750acad2b1eSDavid Xu (void) memcpy(&uc, ucp, sizeof(uc)); 7518bbeb7e9SDavid Xu SIGDELSET(uc.uc_sigmask, SIGCANCEL); 7528bbeb7e9SDavid Xu ucp = &uc; 7538bbeb7e9SDavid Xu } 7548bbeb7e9SDavid Xu return __sys_swapcontext(oucp, ucp); 755acad2b1eSDavid Xu } 756