thr_sig.c revision 277640
1224857Snwhitehorn/* 2224857Snwhitehorn * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3224857Snwhitehorn * All rights reserved. 4224857Snwhitehorn * 5224857Snwhitehorn * Redistribution and use in source and binary forms, with or without 6224857Snwhitehorn * modification, are permitted provided that the following conditions 7224857Snwhitehorn * are met: 8224857Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9224857Snwhitehorn * notice unmodified, this list of conditions, and the following 10224857Snwhitehorn * disclaimer. 11224857Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 12224857Snwhitehorn * notice, this list of conditions and the following disclaimer in the 13224857Snwhitehorn * documentation and/or other materials provided with the distribution. 14224857Snwhitehorn * 15224857Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16224857Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17224857Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18224857Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19224857Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20224857Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21224857Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22224857Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23224857Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24224857Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25224857Snwhitehorn * 26224857Snwhitehorn * $FreeBSD: stable/10/lib/libthr/thread/thr_sig.c 277640 2015-01-24 08:35:49Z kib $ 27224857Snwhitehorn */ 28224857Snwhitehorn 29224857Snwhitehorn#include "namespace.h" 30224857Snwhitehorn#include <sys/param.h> 31224857Snwhitehorn#include <sys/types.h> 32224857Snwhitehorn#include <sys/signalvar.h> 33224857Snwhitehorn#include <signal.h> 34224857Snwhitehorn#include <errno.h> 35224857Snwhitehorn#include <stdlib.h> 36224857Snwhitehorn#include <string.h> 37224857Snwhitehorn#include <pthread.h> 38224857Snwhitehorn#include "un-namespace.h" 39224857Snwhitehorn#include "libc_private.h" 40224857Snwhitehorn 41224857Snwhitehorn#include "libc_private.h" 42224857Snwhitehorn#include "thr_private.h" 43224857Snwhitehorn 44224857Snwhitehorn/* #define DEBUG_SIGNAL */ 45224857Snwhitehorn#ifdef DEBUG_SIGNAL 46224857Snwhitehorn#define DBG_MSG stdout_debug 47224857Snwhitehorn#else 48224857Snwhitehorn#define DBG_MSG(x...) 49224857Snwhitehorn#endif 50224857Snwhitehorn 51224857Snwhitehornstruct usigaction { 52224857Snwhitehorn struct sigaction sigact; 53224857Snwhitehorn struct urwlock lock; 54224857Snwhitehorn}; 55224857Snwhitehorn 56224857Snwhitehornstatic struct usigaction _thr_sigact[_SIG_MAXSIG]; 57224857Snwhitehorn 58224857Snwhitehornstatic inline struct usigaction * 59224857Snwhitehorn__libc_sigaction_slot(int signo) 60224857Snwhitehorn{ 61224857Snwhitehorn 62224857Snwhitehorn return (&_thr_sigact[signo - 1]); 63224857Snwhitehorn} 64224857Snwhitehorn 65224857Snwhitehornstatic void thr_sighandler(int, siginfo_t *, void *); 66224857Snwhitehornstatic void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *); 67224857Snwhitehornstatic void check_deferred_signal(struct pthread *); 68224857Snwhitehornstatic void check_suspend(struct pthread *); 69224857Snwhitehornstatic void check_cancel(struct pthread *curthread, ucontext_t *ucp); 70224857Snwhitehorn 71224857Snwhitehornint _sigtimedwait(const sigset_t *set, siginfo_t *info, 72224857Snwhitehorn const struct timespec * timeout); 73224857Snwhitehornint _sigwaitinfo(const sigset_t *set, siginfo_t *info); 74224857Snwhitehornint _sigwait(const sigset_t *set, int *sig); 75224857Snwhitehornint _setcontext(const ucontext_t *); 76224857Snwhitehornint _swapcontext(ucontext_t *, const ucontext_t *); 77224857Snwhitehorn 78224857Snwhitehornstatic const sigset_t _thr_deferset={{ 79224857Snwhitehorn 0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)| 80224857Snwhitehorn _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)), 81224857Snwhitehorn 0xffffffff, 82224857Snwhitehorn 0xffffffff, 83224857Snwhitehorn 0xffffffff}}; 84224857Snwhitehorn 85224857Snwhitehornstatic const sigset_t _thr_maskset={{ 86224857Snwhitehorn 0xffffffff, 87224857Snwhitehorn 0xffffffff, 88224857Snwhitehorn 0xffffffff, 89224857Snwhitehorn 0xffffffff}}; 90224857Snwhitehorn 91224857Snwhitehornvoid 92224857Snwhitehorn_thr_signal_block(struct pthread *curthread) 93224857Snwhitehorn{ 94224857Snwhitehorn 95224857Snwhitehorn if (curthread->sigblock > 0) { 96224857Snwhitehorn curthread->sigblock++; 97224857Snwhitehorn return; 98224857Snwhitehorn } 99224857Snwhitehorn __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask); 100224857Snwhitehorn curthread->sigblock++; 101224857Snwhitehorn} 102224857Snwhitehorn 103224857Snwhitehornvoid 104224857Snwhitehorn_thr_signal_unblock(struct pthread *curthread) 105224857Snwhitehorn{ 106224857Snwhitehorn if (--curthread->sigblock == 0) 107224857Snwhitehorn __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 108224857Snwhitehorn} 109224857Snwhitehorn 110224857Snwhitehornint 111224857Snwhitehorn_thr_send_sig(struct pthread *thread, int sig) 112224857Snwhitehorn{ 113224857Snwhitehorn return thr_kill(thread->tid, sig); 114224857Snwhitehorn} 115224857Snwhitehorn 116224857Snwhitehornstatic inline void 117224857Snwhitehornremove_thr_signals(sigset_t *set) 118224857Snwhitehorn{ 119224857Snwhitehorn if (SIGISMEMBER(*set, SIGCANCEL)) 120224857Snwhitehorn SIGDELSET(*set, SIGCANCEL); 121224857Snwhitehorn} 122224857Snwhitehorn 123224857Snwhitehornstatic const sigset_t * 124224857Snwhitehornthr_remove_thr_signals(const sigset_t *set, sigset_t *newset) 125224857Snwhitehorn{ 126224857Snwhitehorn *newset = *set; 127224857Snwhitehorn remove_thr_signals(newset); 128224857Snwhitehorn return (newset); 129224857Snwhitehorn} 130224857Snwhitehorn 131224857Snwhitehornstatic void 132224857Snwhitehornsigcancel_handler(int sig __unused, 133224857Snwhitehorn siginfo_t *info __unused, ucontext_t *ucp) 134224857Snwhitehorn{ 135224857Snwhitehorn struct pthread *curthread = _get_curthread(); 136224857Snwhitehorn int err; 137224857Snwhitehorn 138224857Snwhitehorn if (THR_IN_CRITICAL(curthread)) 139224857Snwhitehorn return; 140224857Snwhitehorn err = errno; 141224857Snwhitehorn check_suspend(curthread); 142224857Snwhitehorn check_cancel(curthread, ucp); 143224857Snwhitehorn errno = err; 144224857Snwhitehorn} 145224857Snwhitehorn 146224857Snwhitehorntypedef void (*ohandler)(int sig, int code, struct sigcontext *scp, 147224857Snwhitehorn char *addr, __sighandler_t *catcher); 148224857Snwhitehorn 149224857Snwhitehorn/* 150224857Snwhitehorn * The signal handler wrapper is entered with all signal masked. 151224857Snwhitehorn */ 152224857Snwhitehornstatic void 153224857Snwhitehornthr_sighandler(int sig, siginfo_t *info, void *_ucp) 154224857Snwhitehorn{ 155224857Snwhitehorn struct pthread *curthread; 156224857Snwhitehorn ucontext_t *ucp; 157224857Snwhitehorn struct sigaction act; 158224857Snwhitehorn struct usigaction *usa; 159224857Snwhitehorn int err; 160224857Snwhitehorn 161224857Snwhitehorn err = errno; 162224857Snwhitehorn curthread = _get_curthread(); 163224857Snwhitehorn ucp = _ucp; 164224857Snwhitehorn usa = __libc_sigaction_slot(sig); 165224857Snwhitehorn _thr_rwl_rdlock(&usa->lock); 166224857Snwhitehorn act = usa->sigact; 167224857Snwhitehorn _thr_rwl_unlock(&usa->lock); 168224857Snwhitehorn errno = err; 169224857Snwhitehorn curthread->deferred_run = 0; 170224857Snwhitehorn 171224857Snwhitehorn /* 172224857Snwhitehorn * if a thread is in critical region, for example it holds low level locks, 173224857Snwhitehorn * try to defer the signal processing, however if the signal is synchronous 174224857Snwhitehorn * signal, it means a bad thing has happened, this is a programming error, 175224857Snwhitehorn * resuming fault point can not help anything (normally causes deadloop), 176224857Snwhitehorn * so here we let user code handle it immediately. 177224857Snwhitehorn */ 178224857Snwhitehorn if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) { 179224857Snwhitehorn memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction)); 180224857Snwhitehorn memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t)); 181224857Snwhitehorn curthread->deferred_sigmask = ucp->uc_sigmask; 182224857Snwhitehorn /* mask all signals, we will restore it later. */ 183224857Snwhitehorn ucp->uc_sigmask = _thr_deferset; 184224857Snwhitehorn return; 185224857Snwhitehorn } 186224857Snwhitehorn 187224857Snwhitehorn handle_signal(&act, sig, info, ucp); 188224857Snwhitehorn} 189224857Snwhitehorn 190224857Snwhitehornstatic void 191224857Snwhitehornhandle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) 192224857Snwhitehorn{ 193224857Snwhitehorn struct pthread *curthread = _get_curthread(); 194224857Snwhitehorn ucontext_t uc2; 195224857Snwhitehorn __siginfohandler_t *sigfunc; 196224857Snwhitehorn int cancel_point; 197224857Snwhitehorn int cancel_async; 198224857Snwhitehorn int cancel_enable; 199224857Snwhitehorn int in_sigsuspend; 200224857Snwhitehorn int err; 201224857Snwhitehorn 202224857Snwhitehorn /* add previous level mask */ 203224857Snwhitehorn SIGSETOR(actp->sa_mask, ucp->uc_sigmask); 204224857Snwhitehorn 205224857Snwhitehorn /* add this signal's mask */ 206224857Snwhitehorn if (!(actp->sa_flags & SA_NODEFER)) 207224857Snwhitehorn SIGADDSET(actp->sa_mask, sig); 208224857Snwhitehorn 209224857Snwhitehorn in_sigsuspend = curthread->in_sigsuspend; 210224857Snwhitehorn curthread->in_sigsuspend = 0; 211224857Snwhitehorn 212224857Snwhitehorn /* 213224857Snwhitehorn * If thread is in deferred cancellation mode, disable cancellation 214224857Snwhitehorn * in signal handler. 215224857Snwhitehorn * If user signal handler calls a cancellation point function, e.g, 216224857Snwhitehorn * it calls write() to write data to file, because write() is a 217224857Snwhitehorn * cancellation point, the thread is immediately cancelled if 218224857Snwhitehorn * cancellation is pending, to avoid this problem while thread is in 219224857Snwhitehorn * deferring mode, cancellation is temporarily disabled. 220224857Snwhitehorn */ 221224857Snwhitehorn cancel_point = curthread->cancel_point; 222224857Snwhitehorn cancel_async = curthread->cancel_async; 223224857Snwhitehorn cancel_enable = curthread->cancel_enable; 224224857Snwhitehorn curthread->cancel_point = 0; 225224857Snwhitehorn if (!cancel_async) 226224857Snwhitehorn curthread->cancel_enable = 0; 227224857Snwhitehorn 228224857Snwhitehorn /* restore correct mask before calling user handler */ 229224857Snwhitehorn __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL); 230224857Snwhitehorn 231224857Snwhitehorn sigfunc = actp->sa_sigaction; 232224857Snwhitehorn 233224857Snwhitehorn /* 234224857Snwhitehorn * We have already reset cancellation point flags, so if user's code 235224857Snwhitehorn * longjmp()s out of its signal handler, wish its jmpbuf was set 236224857Snwhitehorn * outside of a cancellation point, in most cases, this would be 237224857Snwhitehorn * true. However, there is no way to save cancel_enable in jmpbuf, 238224857Snwhitehorn * so after setjmps() returns once more, the user code may need to 239224857Snwhitehorn * re-set cancel_enable flag by calling pthread_setcancelstate(). 240224857Snwhitehorn */ 241224857Snwhitehorn if ((actp->sa_flags & SA_SIGINFO) != 0) { 242224857Snwhitehorn sigfunc(sig, info, ucp); 243224857Snwhitehorn } else { 244224857Snwhitehorn ((ohandler)sigfunc)(sig, info->si_code, 245224857Snwhitehorn (struct sigcontext *)ucp, info->si_addr, 246224857Snwhitehorn (__sighandler_t *)sigfunc); 247224857Snwhitehorn } 248224857Snwhitehorn err = errno; 249224857Snwhitehorn 250224857Snwhitehorn curthread->in_sigsuspend = in_sigsuspend; 251224857Snwhitehorn curthread->cancel_point = cancel_point; 252224857Snwhitehorn curthread->cancel_enable = cancel_enable; 253224857Snwhitehorn 254224857Snwhitehorn memcpy(&uc2, ucp, sizeof(uc2)); 255224857Snwhitehorn SIGDELSET(uc2.uc_sigmask, SIGCANCEL); 256224857Snwhitehorn 257224857Snwhitehorn /* reschedule cancellation */ 258224857Snwhitehorn check_cancel(curthread, &uc2); 259224857Snwhitehorn errno = err; 260224857Snwhitehorn __sys_sigreturn(&uc2); 261224857Snwhitehorn} 262224857Snwhitehorn 263224857Snwhitehornvoid 264224857Snwhitehorn_thr_ast(struct pthread *curthread) 265224857Snwhitehorn{ 266224857Snwhitehorn 267224857Snwhitehorn if (!THR_IN_CRITICAL(curthread)) { 268224857Snwhitehorn check_deferred_signal(curthread); 269224857Snwhitehorn check_suspend(curthread); 270224857Snwhitehorn check_cancel(curthread, NULL); 271224857Snwhitehorn } 272224857Snwhitehorn} 273224857Snwhitehorn 274224857Snwhitehorn/* reschedule cancellation */ 275224857Snwhitehornstatic void 276224857Snwhitehorncheck_cancel(struct pthread *curthread, ucontext_t *ucp) 277224857Snwhitehorn{ 278224857Snwhitehorn 279224857Snwhitehorn if (__predict_true(!curthread->cancel_pending || 280224857Snwhitehorn !curthread->cancel_enable || curthread->no_cancel)) 281224857Snwhitehorn return; 282224857Snwhitehorn 283224857Snwhitehorn /* 284224857Snwhitehorn * Otherwise, we are in defer mode, and we are at 285224857Snwhitehorn * cancel point, tell kernel to not block the current 286224857Snwhitehorn * thread on next cancelable system call. 287224857Snwhitehorn * 288224857Snwhitehorn * There are three cases we should call thr_wake() to 289224857Snwhitehorn * turn on TDP_WAKEUP or send SIGCANCEL in kernel: 290224857Snwhitehorn * 1) we are going to call a cancelable system call, 291224857Snwhitehorn * non-zero cancel_point means we are already in 292224857Snwhitehorn * cancelable state, next system call is cancelable. 293224857Snwhitehorn * 2) because _thr_ast() may be called by 294224857Snwhitehorn * THR_CRITICAL_LEAVE() which is used by rtld rwlock 295224857Snwhitehorn * and any libthr internal locks, when rtld rwlock 296224857Snwhitehorn * is used, it is mostly caused my an unresolved PLT. 297224857Snwhitehorn * those routines may clear the TDP_WAKEUP flag by 298224857Snwhitehorn * invoking some system calls, in those cases, we 299224857Snwhitehorn * also should reenable the flag. 300224857Snwhitehorn * 3) thread is in sigsuspend(), and the syscall insists 301224857Snwhitehorn * on getting a signal before it agrees to return. 302224857Snwhitehorn */ 303224857Snwhitehorn if (curthread->cancel_point) { 304224857Snwhitehorn if (curthread->in_sigsuspend && ucp) { 305224857Snwhitehorn SIGADDSET(ucp->uc_sigmask, SIGCANCEL); 306224857Snwhitehorn curthread->unblock_sigcancel = 1; 307224857Snwhitehorn _thr_send_sig(curthread, SIGCANCEL); 308224857Snwhitehorn } else 309224857Snwhitehorn thr_wake(curthread->tid); 310224857Snwhitehorn } else if (curthread->cancel_async) { 311224857Snwhitehorn /* 312224857Snwhitehorn * asynchronous cancellation mode, act upon 313224857Snwhitehorn * immediately. 314224857Snwhitehorn */ 315224857Snwhitehorn _pthread_exit_mask(PTHREAD_CANCELED, 316224857Snwhitehorn ucp? &ucp->uc_sigmask : NULL); 317224857Snwhitehorn } 318224857Snwhitehorn} 319224857Snwhitehorn 320224857Snwhitehornstatic void 321224857Snwhitehorncheck_deferred_signal(struct pthread *curthread) 322224857Snwhitehorn{ 323224857Snwhitehorn ucontext_t *uc; 324224857Snwhitehorn struct sigaction act; 325224857Snwhitehorn siginfo_t info; 326224857Snwhitehorn int uc_len; 327224857Snwhitehorn 328224857Snwhitehorn if (__predict_true(curthread->deferred_siginfo.si_signo == 0 || 329224857Snwhitehorn curthread->deferred_run)) 330224857Snwhitehorn return; 331224857Snwhitehorn 332224857Snwhitehorn curthread->deferred_run = 1; 333224857Snwhitehorn uc_len = __getcontextx_size(); 334224857Snwhitehorn uc = alloca(uc_len); 335224857Snwhitehorn getcontext(uc); 336224857Snwhitehorn if (curthread->deferred_siginfo.si_signo == 0) { 337224857Snwhitehorn curthread->deferred_run = 0; 338224857Snwhitehorn return; 339224857Snwhitehorn } 340224857Snwhitehorn __fillcontextx2((char *)uc); 341224857Snwhitehorn act = curthread->deferred_sigact; 342224857Snwhitehorn uc->uc_sigmask = curthread->deferred_sigmask; 343224857Snwhitehorn memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t)); 344224857Snwhitehorn /* remove signal */ 345224857Snwhitehorn curthread->deferred_siginfo.si_signo = 0; 346224857Snwhitehorn handle_signal(&act, info.si_signo, &info, uc); 347224857Snwhitehorn} 348224857Snwhitehorn 349224857Snwhitehornstatic void 350224857Snwhitehorncheck_suspend(struct pthread *curthread) 351224857Snwhitehorn{ 352224857Snwhitehorn uint32_t cycle; 353224857Snwhitehorn 354224857Snwhitehorn if (__predict_true((curthread->flags & 355224857Snwhitehorn (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 356224857Snwhitehorn != THR_FLAGS_NEED_SUSPEND)) 357224857Snwhitehorn return; 358224857Snwhitehorn if (curthread == _single_thread) 359224857Snwhitehorn return; 360224857Snwhitehorn if (curthread->force_exit) 361224857Snwhitehorn return; 362224857Snwhitehorn 363224857Snwhitehorn /* 364224857Snwhitehorn * Blocks SIGCANCEL which other threads must send. 365224857Snwhitehorn */ 366224857Snwhitehorn _thr_signal_block(curthread); 367224857Snwhitehorn 368224857Snwhitehorn /* 369224857Snwhitehorn * Increase critical_count, here we don't use THR_LOCK/UNLOCK 370224857Snwhitehorn * because we are leaf code, we don't want to recursively call 371224857Snwhitehorn * ourself. 372246713Skib */ 373246713Skib curthread->critical_count++; 374224857Snwhitehorn THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 375224857Snwhitehorn while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 376224857Snwhitehorn THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 377224857Snwhitehorn curthread->cycle++; 378224857Snwhitehorn cycle = curthread->cycle; 379224857Snwhitehorn 380224857Snwhitehorn /* Wake the thread suspending us. */ 381224857Snwhitehorn _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 382224857Snwhitehorn 383224857Snwhitehorn /* 384224857Snwhitehorn * if we are from pthread_exit, we don't want to 385224857Snwhitehorn * suspend, just go and die. 386224857Snwhitehorn */ 387224857Snwhitehorn if (curthread->state == PS_DEAD) 388224857Snwhitehorn break; 389224857Snwhitehorn curthread->flags |= THR_FLAGS_SUSPENDED; 390224857Snwhitehorn THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 391224857Snwhitehorn _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0); 392224857Snwhitehorn THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 393224857Snwhitehorn curthread->flags &= ~THR_FLAGS_SUSPENDED; 394224857Snwhitehorn } 395224857Snwhitehorn THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 396224857Snwhitehorn curthread->critical_count--; 397224857Snwhitehorn 398224857Snwhitehorn _thr_signal_unblock(curthread); 399224857Snwhitehorn} 400224857Snwhitehorn 401224857Snwhitehornvoid 402224857Snwhitehorn_thr_signal_init(int dlopened) 403224857Snwhitehorn{ 404224857Snwhitehorn struct sigaction act, nact, oact; 405224857Snwhitehorn struct usigaction *usa; 406224857Snwhitehorn sigset_t oldset; 407224857Snwhitehorn int sig, error; 408224857Snwhitehorn 409224857Snwhitehorn if (dlopened) { 410224857Snwhitehorn __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 411224857Snwhitehorn for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 412224857Snwhitehorn if (sig == SIGCANCEL) 413224857Snwhitehorn continue; 414224857Snwhitehorn error = __sys_sigaction(sig, NULL, &oact); 415224857Snwhitehorn if (error == -1 || oact.sa_handler == SIG_DFL || 416224857Snwhitehorn oact.sa_handler == SIG_IGN) 417224857Snwhitehorn continue; 418224857Snwhitehorn usa = __libc_sigaction_slot(sig); 419224857Snwhitehorn usa->sigact = oact; 420224857Snwhitehorn nact = oact; 421224857Snwhitehorn remove_thr_signals(&usa->sigact.sa_mask); 422224857Snwhitehorn nact.sa_flags &= ~SA_NODEFER; 423224857Snwhitehorn nact.sa_flags |= SA_SIGINFO; 424315813Smav nact.sa_sigaction = thr_sighandler; 425315813Smav nact.sa_mask = _thr_maskset; 426315813Smav (void)__sys_sigaction(sig, &nact, NULL); 427224857Snwhitehorn } 428224857Snwhitehorn __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 429224857Snwhitehorn } 430224857Snwhitehorn 431224857Snwhitehorn /* Install SIGCANCEL handler. */ 432224857Snwhitehorn SIGFILLSET(act.sa_mask); 433224857Snwhitehorn act.sa_flags = SA_SIGINFO; 434224857Snwhitehorn act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 435224857Snwhitehorn __sys_sigaction(SIGCANCEL, &act, NULL); 436224857Snwhitehorn 437224857Snwhitehorn /* Unblock SIGCANCEL */ 438224857Snwhitehorn SIGEMPTYSET(act.sa_mask); 439224857Snwhitehorn SIGADDSET(act.sa_mask, SIGCANCEL); 440224857Snwhitehorn __sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL); 441224857Snwhitehorn} 442224857Snwhitehorn 443224857Snwhitehornvoid 444224857Snwhitehorn_thr_sigact_unload(struct dl_phdr_info *phdr_info) 445224857Snwhitehorn{ 446224857Snwhitehorn#if 0 447224857Snwhitehorn struct pthread *curthread = _get_curthread(); 448224857Snwhitehorn struct urwlock *rwlp; 449224857Snwhitehorn struct sigaction *actp; 450224857Snwhitehorn struct usigaction *usa; 451224857Snwhitehorn struct sigaction kact; 452224857Snwhitehorn void (*handler)(int); 453224857Snwhitehorn int sig; 454224857Snwhitehorn 455224857Snwhitehorn _thr_signal_block(curthread); 456224857Snwhitehorn for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 457224857Snwhitehorn usa = __libc_sigaction_slot(sig); 458224857Snwhitehorn actp = &usa->sigact; 459224857Snwhitehornretry: 460224857Snwhitehorn handler = actp->sa_handler; 461224857Snwhitehorn if (handler != SIG_DFL && handler != SIG_IGN && 462224857Snwhitehorn __elf_phdr_match_addr(phdr_info, handler)) { 463224857Snwhitehorn rwlp = &usa->lock; 464224857Snwhitehorn _thr_rwl_wrlock(rwlp); 465224857Snwhitehorn if (handler != actp->sa_handler) { 466224857Snwhitehorn _thr_rwl_unlock(rwlp); 467224857Snwhitehorn goto retry; 468224857Snwhitehorn } 469224857Snwhitehorn actp->sa_handler = SIG_DFL; 470224857Snwhitehorn actp->sa_flags = SA_SIGINFO; 471224857Snwhitehorn SIGEMPTYSET(actp->sa_mask); 472224857Snwhitehorn if (__sys_sigaction(sig, NULL, &kact) == 0 && 473224857Snwhitehorn kact.sa_handler != SIG_DFL && 474224857Snwhitehorn kact.sa_handler != SIG_IGN) 475224857Snwhitehorn __sys_sigaction(sig, actp, NULL); 476224857Snwhitehorn _thr_rwl_unlock(rwlp); 477224857Snwhitehorn } 478224857Snwhitehorn } 479224857Snwhitehorn _thr_signal_unblock(curthread); 480224857Snwhitehorn#endif 481224857Snwhitehorn} 482224857Snwhitehorn 483224857Snwhitehornvoid 484224857Snwhitehorn_thr_signal_prefork(void) 485224857Snwhitehorn{ 486224857Snwhitehorn int i; 487224857Snwhitehorn 488224857Snwhitehorn for (i = 1; i <= _SIG_MAXSIG; ++i) 489224857Snwhitehorn _thr_rwl_rdlock(&__libc_sigaction_slot(i)->lock); 490224857Snwhitehorn} 491224857Snwhitehorn 492224857Snwhitehornvoid 493224857Snwhitehorn_thr_signal_postfork(void) 494224857Snwhitehorn{ 495224857Snwhitehorn int i; 496224857Snwhitehorn 497224857Snwhitehorn for (i = 1; i <= _SIG_MAXSIG; ++i) 498224857Snwhitehorn _thr_rwl_unlock(&__libc_sigaction_slot(i)->lock); 499224857Snwhitehorn} 500224857Snwhitehorn 501224857Snwhitehornvoid 502224857Snwhitehorn_thr_signal_postfork_child(void) 503224857Snwhitehorn{ 504224857Snwhitehorn int i; 505224857Snwhitehorn 506224857Snwhitehorn for (i = 1; i <= _SIG_MAXSIG; ++i) { 507224857Snwhitehorn bzero(&__libc_sigaction_slot(i) -> lock, 508224857Snwhitehorn sizeof(struct urwlock)); 509224857Snwhitehorn } 510224857Snwhitehorn} 511224857Snwhitehorn 512224857Snwhitehornvoid 513225950Sken_thr_signal_deinit(void) 514225950Sken{ 515225950Sken} 516225950Sken 517225950Skenint 518225950Sken__thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) 519225950Sken{ 520225950Sken struct sigaction newact, oldact, oldact2; 521224857Snwhitehorn sigset_t oldset; 522224857Snwhitehorn struct usigaction *usa; 523224857Snwhitehorn int ret, err; 524224857Snwhitehorn 525224857Snwhitehorn if (!_SIG_VALID(sig) || sig == SIGCANCEL) { 526224857Snwhitehorn errno = EINVAL; 527224857Snwhitehorn return (-1); 528224857Snwhitehorn } 529224857Snwhitehorn 530224857Snwhitehorn ret = 0; 531224857Snwhitehorn err = 0; 532224857Snwhitehorn usa = __libc_sigaction_slot(sig); 533224857Snwhitehorn 534224857Snwhitehorn __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 535224857Snwhitehorn _thr_rwl_wrlock(&usa->lock); 536224857Snwhitehorn 537224857Snwhitehorn if (act != NULL) { 538224857Snwhitehorn oldact2 = usa->sigact; 539224857Snwhitehorn newact = *act; 540224857Snwhitehorn 541224857Snwhitehorn /* 542224857Snwhitehorn * if a new sig handler is SIG_DFL or SIG_IGN, 543224857Snwhitehorn * don't remove old handler from __libc_sigact[], 544224857Snwhitehorn * so deferred signals still can use the handlers, 545224857Snwhitehorn * multiple threads invoking sigaction itself is 546224857Snwhitehorn * a race condition, so it is not a problem. 547224857Snwhitehorn */ 548224857Snwhitehorn if (newact.sa_handler != SIG_DFL && 549224857Snwhitehorn newact.sa_handler != SIG_IGN) { 550224857Snwhitehorn usa->sigact = newact; 551224857Snwhitehorn remove_thr_signals(&usa->sigact.sa_mask); 552224857Snwhitehorn newact.sa_flags &= ~SA_NODEFER; 553224857Snwhitehorn newact.sa_flags |= SA_SIGINFO; 554224857Snwhitehorn newact.sa_sigaction = thr_sighandler; 555224857Snwhitehorn newact.sa_mask = _thr_maskset; /* mask all signals */ 556224857Snwhitehorn } 557224857Snwhitehorn ret = __sys_sigaction(sig, &newact, &oldact); 558224857Snwhitehorn if (ret == -1) { 559224857Snwhitehorn err = errno; 560255943Snwhitehorn usa->sigact = oldact2; 561255943Snwhitehorn } 562255943Snwhitehorn } else if (oact != NULL) { 563224857Snwhitehorn ret = __sys_sigaction(sig, NULL, &oldact); 564224857Snwhitehorn err = errno; 565224857Snwhitehorn } 566224857Snwhitehorn 567224857Snwhitehorn if (oldact.sa_handler != SIG_DFL && oldact.sa_handler != SIG_IGN) { 568224857Snwhitehorn if (act != NULL) 569224857Snwhitehorn oldact = oldact2; 570224857Snwhitehorn else if (oact != NULL) 571224857Snwhitehorn oldact = usa->sigact; 572224857Snwhitehorn } 573224857Snwhitehorn 574224857Snwhitehorn _thr_rwl_unlock(&usa->lock); 575224857Snwhitehorn __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 576224857Snwhitehorn 577224857Snwhitehorn if (ret == 0) { 578224857Snwhitehorn if (oact != NULL) 579224857Snwhitehorn *oact = oldact; 580224857Snwhitehorn } else { 581224857Snwhitehorn errno = err; 582224857Snwhitehorn } 583224857Snwhitehorn return (ret); 584224857Snwhitehorn} 585224857Snwhitehorn 586255943Snwhitehornint 587224857Snwhitehorn__thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset) 588224857Snwhitehorn{ 589224857Snwhitehorn const sigset_t *p = set; 590224857Snwhitehorn sigset_t newset; 591224857Snwhitehorn 592224857Snwhitehorn if (how != SIG_UNBLOCK) { 593224857Snwhitehorn if (set != NULL) { 594224857Snwhitehorn newset = *set; 595224857Snwhitehorn SIGDELSET(newset, SIGCANCEL); 596224857Snwhitehorn p = &newset; 597224857Snwhitehorn } 598255943Snwhitehorn } 599224857Snwhitehorn return (__sys_sigprocmask(how, p, oset)); 600224857Snwhitehorn} 601224857Snwhitehorn 602224857Snwhitehorn__weak_reference(_pthread_sigmask, pthread_sigmask); 603224857Snwhitehorn 604224857Snwhitehornint 605224857Snwhitehorn_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 606224857Snwhitehorn{ 607224857Snwhitehorn 608224857Snwhitehorn if (__thr_sigprocmask(how, set, oset)) 609224857Snwhitehorn return (errno); 610224857Snwhitehorn return (0); 611224857Snwhitehorn} 612224857Snwhitehorn 613224857Snwhitehornint 614224857Snwhitehorn_sigsuspend(const sigset_t * set) 615224857Snwhitehorn{ 616224857Snwhitehorn sigset_t newset; 617224857Snwhitehorn 618224857Snwhitehorn return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset))); 619224857Snwhitehorn} 620224857Snwhitehorn 621224857Snwhitehornint 622224857Snwhitehorn__thr_sigsuspend(const sigset_t * set) 623224857Snwhitehorn{ 624224857Snwhitehorn struct pthread *curthread; 625224857Snwhitehorn sigset_t newset; 626224857Snwhitehorn int ret, old; 627224857Snwhitehorn 628224857Snwhitehorn curthread = _get_curthread(); 629255943Snwhitehorn 630255943Snwhitehorn old = curthread->in_sigsuspend; 631224857Snwhitehorn curthread->in_sigsuspend = 1; 632255943Snwhitehorn _thr_cancel_enter(curthread); 633224857Snwhitehorn ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); 634224857Snwhitehorn _thr_cancel_leave(curthread, 1); 635224857Snwhitehorn curthread->in_sigsuspend = old; 636224857Snwhitehorn if (curthread->unblock_sigcancel) { 637224857Snwhitehorn curthread->unblock_sigcancel = 0; 638224857Snwhitehorn SIGEMPTYSET(newset); 639224857Snwhitehorn SIGADDSET(newset, SIGCANCEL); 640224857Snwhitehorn __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL); 641224857Snwhitehorn } 642224857Snwhitehorn 643224857Snwhitehorn return (ret); 644224857Snwhitehorn} 645224857Snwhitehorn 646224857Snwhitehornint 647224857Snwhitehorn_sigtimedwait(const sigset_t *set, siginfo_t *info, 648224857Snwhitehorn const struct timespec * timeout) 649224857Snwhitehorn{ 650224857Snwhitehorn sigset_t newset; 651224857Snwhitehorn 652224857Snwhitehorn return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 653224857Snwhitehorn timeout)); 654224857Snwhitehorn} 655224857Snwhitehorn 656225950Sken/* 657225950Sken * Cancellation behavior: 658225950Sken * Thread may be canceled at start, if thread got signal, 659225950Sken * it is not canceled. 660225950Sken */ 661225950Skenint 662225950Sken__thr_sigtimedwait(const sigset_t *set, siginfo_t *info, 663225950Sken const struct timespec * timeout) 664225950Sken{ 665225950Sken struct pthread *curthread = _get_curthread(); 666225950Sken sigset_t newset; 667225950Sken int ret; 668224857Snwhitehorn 669224857Snwhitehorn _thr_cancel_enter(curthread); 670224857Snwhitehorn ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 671224857Snwhitehorn timeout); 672224857Snwhitehorn _thr_cancel_leave(curthread, (ret == -1)); 673224857Snwhitehorn return (ret); 674224857Snwhitehorn} 675224857Snwhitehorn 676224857Snwhitehornint 677224857Snwhitehorn_sigwaitinfo(const sigset_t *set, siginfo_t *info) 678224857Snwhitehorn{ 679224857Snwhitehorn sigset_t newset; 680224857Snwhitehorn 681224857Snwhitehorn return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info)); 682224857Snwhitehorn} 683224857Snwhitehorn 684224857Snwhitehorn/* 685224857Snwhitehorn * Cancellation behavior: 686224857Snwhitehorn * Thread may be canceled at start, if thread got signal, 687224857Snwhitehorn * it is not canceled. 688224857Snwhitehorn */ 689224857Snwhitehornint 690224857Snwhitehorn__thr_sigwaitinfo(const sigset_t *set, siginfo_t *info) 691224857Snwhitehorn{ 692224857Snwhitehorn struct pthread *curthread = _get_curthread(); 693224857Snwhitehorn sigset_t newset; 694224857Snwhitehorn int ret; 695224857Snwhitehorn 696224857Snwhitehorn _thr_cancel_enter(curthread); 697224857Snwhitehorn ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info); 698224857Snwhitehorn _thr_cancel_leave(curthread, ret == -1); 699224857Snwhitehorn return (ret); 700224857Snwhitehorn} 701224857Snwhitehorn 702224857Snwhitehornint 703224857Snwhitehorn_sigwait(const sigset_t *set, int *sig) 704224857Snwhitehorn{ 705224857Snwhitehorn sigset_t newset; 706224857Snwhitehorn 707224857Snwhitehorn return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig)); 708224857Snwhitehorn} 709224857Snwhitehorn 710224857Snwhitehorn/* 711 * Cancellation behavior: 712 * Thread may be canceled at start, if thread got signal, 713 * it is not canceled. 714 */ 715int 716__thr_sigwait(const sigset_t *set, int *sig) 717{ 718 struct pthread *curthread = _get_curthread(); 719 sigset_t newset; 720 int ret; 721 722 do { 723 _thr_cancel_enter(curthread); 724 ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig); 725 _thr_cancel_leave(curthread, (ret != 0)); 726 } while (ret == EINTR); 727 return (ret); 728} 729 730int 731__thr_setcontext(const ucontext_t *ucp) 732{ 733 ucontext_t uc; 734 735 if (ucp == NULL) { 736 errno = EINVAL; 737 return (-1); 738 } 739 if (!SIGISMEMBER(uc.uc_sigmask, SIGCANCEL)) 740 return __sys_setcontext(ucp); 741 (void) memcpy(&uc, ucp, sizeof(uc)); 742 SIGDELSET(uc.uc_sigmask, SIGCANCEL); 743 return (__sys_setcontext(&uc)); 744} 745 746int 747__thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 748{ 749 ucontext_t uc; 750 751 if (oucp == NULL || ucp == NULL) { 752 errno = EINVAL; 753 return (-1); 754 } 755 if (SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) { 756 (void) memcpy(&uc, ucp, sizeof(uc)); 757 SIGDELSET(uc.uc_sigmask, SIGCANCEL); 758 ucp = &uc; 759 } 760 return (__sys_swapcontext(oucp, ucp)); 761} 762