thr_sig.c revision 284493
1222900Snp/* 2296471Snp * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3296471Snp * All rights reserved. 4222900Snp * 5222900Snp * Redistribution and use in source and binary forms, with or without 6222900Snp * modification, are permitted provided that the following conditions 7222900Snp * are met: 8222900Snp * 1. Redistributions of source code must retain the above copyright 9222900Snp * notice unmodified, this list of conditions, and the following 10222900Snp * disclaimer. 11222900Snp * 2. Redistributions in binary form must reproduce the above copyright 12222900Snp * notice, this list of conditions and the following disclaimer in the 13222900Snp * documentation and/or other materials provided with the distribution. 14222900Snp * 15222900Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16222900Snp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17222900Snp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18222900Snp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19222900Snp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20222900Snp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21222900Snp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22222900Snp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23222900Snp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24222900Snp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25222900Snp * 26222900Snp * $FreeBSD: stable/10/lib/libthr/thread/thr_sig.c 284493 2015-06-17 04:18:30Z kib $ 27222900Snp */ 28222900Snp 29222900Snp#include "namespace.h" 30222900Snp#include <sys/param.h> 31222900Snp#include <sys/types.h> 32222900Snp#include <sys/signalvar.h> 33222900Snp#include <signal.h> 34222900Snp#include <errno.h> 35222900Snp#include <stdlib.h> 36222900Snp#include <string.h> 37222900Snp#include <pthread.h> 38222900Snp#include "un-namespace.h" 39222900Snp#include "libc_private.h" 40222900Snp 41222900Snp#include "libc_private.h" 42222900Snp#include "thr_private.h" 43222900Snp 44222900Snp/* #define DEBUG_SIGNAL */ 45222900Snp#ifdef DEBUG_SIGNAL 46222900Snp#define DBG_MSG stdout_debug 47222900Snp#else 48222900Snp#define DBG_MSG(x...) 49222900Snp#endif 50222900Snp 51222900Snpstruct usigaction { 52222900Snp struct sigaction sigact; 53222900Snp struct urwlock lock; 54222900Snp}; 55222900Snp 56222900Snpstatic struct usigaction _thr_sigact[_SIG_MAXSIG]; 57222900Snp 58222900Snpstatic inline struct usigaction * 59222900Snp__libc_sigaction_slot(int signo) 60222900Snp{ 61222900Snp 62222900Snp return (&_thr_sigact[signo - 1]); 63222900Snp} 64222900Snp 65222900Snpstatic void thr_sighandler(int, siginfo_t *, void *); 66222900Snpstatic void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *); 67222900Snpstatic void check_deferred_signal(struct pthread *); 68222900Snpstatic void check_suspend(struct pthread *); 69222900Snpstatic void check_cancel(struct pthread *curthread, ucontext_t *ucp); 70222900Snp 71222900Snpint _sigtimedwait(const sigset_t *set, siginfo_t *info, 72222900Snp const struct timespec * timeout); 73222900Snpint _sigwaitinfo(const sigset_t *set, siginfo_t *info); 74222900Snpint _sigwait(const sigset_t *set, int *sig); 75222900Snpint _setcontext(const ucontext_t *); 76222900Snpint _swapcontext(ucontext_t *, const ucontext_t *); 77222900Snp 78222900Snpstatic const sigset_t _thr_deferset={{ 79222900Snp 0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)| 80222900Snp _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)), 81222900Snp 0xffffffff, 82222900Snp 0xffffffff, 83222900Snp 0xffffffff}}; 84222900Snp 85222900Snpstatic const sigset_t _thr_maskset={{ 86222900Snp 0xffffffff, 87222900Snp 0xffffffff, 88222900Snp 0xffffffff, 89222900Snp 0xffffffff}}; 90222900Snp 91222900Snpvoid 92222900Snp_thr_signal_block(struct pthread *curthread) 93222900Snp{ 94222900Snp 95222900Snp if (curthread->sigblock > 0) { 96222900Snp curthread->sigblock++; 97222900Snp return; 98222900Snp } 99222900Snp __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask); 100222900Snp curthread->sigblock++; 101222900Snp} 102222900Snp 103222900Snpvoid 104222900Snp_thr_signal_unblock(struct pthread *curthread) 105222900Snp{ 106222900Snp if (--curthread->sigblock == 0) 107222900Snp __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 108222900Snp} 109222900Snp 110222900Snpint 111222900Snp_thr_send_sig(struct pthread *thread, int sig) 112222900Snp{ 113222900Snp return thr_kill(thread->tid, sig); 114222900Snp} 115222900Snp 116222900Snpstatic inline void 117222900Snpremove_thr_signals(sigset_t *set) 118222900Snp{ 119222900Snp if (SIGISMEMBER(*set, SIGCANCEL)) 120222900Snp SIGDELSET(*set, SIGCANCEL); 121222900Snp} 122222900Snp 123222900Snpstatic const sigset_t * 124222900Snpthr_remove_thr_signals(const sigset_t *set, sigset_t *newset) 125222900Snp{ 126222900Snp *newset = *set; 127222900Snp remove_thr_signals(newset); 128222900Snp return (newset); 129222900Snp} 130222900Snp 131222900Snpstatic void 132222900Snpsigcancel_handler(int sig __unused, 133222900Snp siginfo_t *info __unused, ucontext_t *ucp) 134222900Snp{ 135222900Snp struct pthread *curthread = _get_curthread(); 136222900Snp int err; 137222900Snp 138222900Snp if (THR_IN_CRITICAL(curthread)) 139222900Snp return; 140222900Snp err = errno; 141222900Snp check_suspend(curthread); 142222900Snp check_cancel(curthread, ucp); 143222900Snp errno = err; 144222900Snp} 145222900Snp 146222900Snptypedef void (*ohandler)(int sig, int code, struct sigcontext *scp, 147222900Snp char *addr, __sighandler_t *catcher); 148222900Snp 149222900Snp/* 150222900Snp * The signal handler wrapper is entered with all signal masked. 151222900Snp */ 152222900Snpstatic void 153222900Snpthr_sighandler(int sig, siginfo_t *info, void *_ucp) 154222900Snp{ 155222900Snp struct pthread *curthread; 156222900Snp ucontext_t *ucp; 157222900Snp struct sigaction act; 158222900Snp struct usigaction *usa; 159222900Snp int err; 160222900Snp 161222900Snp err = errno; 162222900Snp curthread = _get_curthread(); 163222900Snp ucp = _ucp; 164222900Snp usa = __libc_sigaction_slot(sig); 165222900Snp _thr_rwl_rdlock(&usa->lock); 166222900Snp act = usa->sigact; 167222900Snp _thr_rwl_unlock(&usa->lock); 168222900Snp errno = err; 169222900Snp curthread->deferred_run = 0; 170222900Snp 171222900Snp /* 172222900Snp * if a thread is in critical region, for example it holds low level locks, 173222900Snp * try to defer the signal processing, however if the signal is synchronous 174222900Snp * signal, it means a bad thing has happened, this is a programming error, 175222900Snp * resuming fault point can not help anything (normally causes deadloop), 176222900Snp * so here we let user code handle it immediately. 177222900Snp */ 178222900Snp if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) { 179222900Snp memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction)); 180222900Snp memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t)); 181222900Snp curthread->deferred_sigmask = ucp->uc_sigmask; 182222900Snp /* mask all signals, we will restore it later. */ 183222900Snp ucp->uc_sigmask = _thr_deferset; 184222900Snp return; 185222900Snp } 186222900Snp 187222900Snp handle_signal(&act, sig, info, ucp); 188222900Snp} 189222900Snp 190222900Snpstatic void 191222900Snphandle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) 192222900Snp{ 193222900Snp struct pthread *curthread = _get_curthread(); 194222900Snp ucontext_t uc2; 195222900Snp __siginfohandler_t *sigfunc; 196222900Snp int cancel_point; 197222900Snp int cancel_async; 198222900Snp int cancel_enable; 199222900Snp int in_sigsuspend; 200222900Snp int err; 201222900Snp 202222900Snp /* add previous level mask */ 203222900Snp SIGSETOR(actp->sa_mask, ucp->uc_sigmask); 204222900Snp 205222900Snp /* add this signal's mask */ 206222900Snp if (!(actp->sa_flags & SA_NODEFER)) 207222900Snp SIGADDSET(actp->sa_mask, sig); 208222900Snp 209222900Snp in_sigsuspend = curthread->in_sigsuspend; 210222900Snp curthread->in_sigsuspend = 0; 211222900Snp 212222900Snp /* 213222900Snp * If thread is in deferred cancellation mode, disable cancellation 214222900Snp * in signal handler. 215222900Snp * If user signal handler calls a cancellation point function, e.g, 216222900Snp * it calls write() to write data to file, because write() is a 217222900Snp * cancellation point, the thread is immediately cancelled if 218222900Snp * cancellation is pending, to avoid this problem while thread is in 219222900Snp * deferring mode, cancellation is temporarily disabled. 220222900Snp */ 221222900Snp cancel_point = curthread->cancel_point; 222222900Snp cancel_async = curthread->cancel_async; 223222900Snp cancel_enable = curthread->cancel_enable; 224222900Snp curthread->cancel_point = 0; 225222900Snp if (!cancel_async) 226222900Snp curthread->cancel_enable = 0; 227222900Snp 228222900Snp /* restore correct mask before calling user handler */ 229222900Snp __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL); 230222900Snp 231222900Snp sigfunc = actp->sa_sigaction; 232222900Snp 233222900Snp /* 234222900Snp * We have already reset cancellation point flags, so if user's code 235222900Snp * longjmp()s out of its signal handler, wish its jmpbuf was set 236222900Snp * outside of a cancellation point, in most cases, this would be 237222900Snp * true. However, there is no way to save cancel_enable in jmpbuf, 238222900Snp * so after setjmps() returns once more, the user code may need to 239222900Snp * re-set cancel_enable flag by calling pthread_setcancelstate(). 240222900Snp */ 241222900Snp if ((actp->sa_flags & SA_SIGINFO) != 0) { 242222900Snp sigfunc(sig, info, ucp); 243222900Snp } else { 244222900Snp ((ohandler)sigfunc)(sig, info->si_code, 245222900Snp (struct sigcontext *)ucp, info->si_addr, 246222900Snp (__sighandler_t *)sigfunc); 247222900Snp } 248222900Snp err = errno; 249222900Snp 250222900Snp curthread->in_sigsuspend = in_sigsuspend; 251222900Snp curthread->cancel_point = cancel_point; 252222900Snp curthread->cancel_enable = cancel_enable; 253222900Snp 254222900Snp memcpy(&uc2, ucp, sizeof(uc2)); 255222900Snp SIGDELSET(uc2.uc_sigmask, SIGCANCEL); 256222900Snp 257222900Snp /* reschedule cancellation */ 258222900Snp check_cancel(curthread, &uc2); 259222900Snp errno = err; 260222900Snp __sys_sigreturn(&uc2); 261222900Snp} 262222900Snp 263222900Snpvoid 264222900Snp_thr_ast(struct pthread *curthread) 265222900Snp{ 266222900Snp 267222900Snp if (!THR_IN_CRITICAL(curthread)) { 268222900Snp check_deferred_signal(curthread); 269222900Snp check_suspend(curthread); 270222900Snp check_cancel(curthread, NULL); 271222900Snp } 272222900Snp} 273222900Snp 274222900Snp/* reschedule cancellation */ 275222900Snpstatic void 276222900Snpcheck_cancel(struct pthread *curthread, ucontext_t *ucp) 277222900Snp{ 278222900Snp 279222900Snp if (__predict_true(!curthread->cancel_pending || 280222900Snp !curthread->cancel_enable || curthread->no_cancel)) 281222900Snp return; 282222900Snp 283222900Snp /* 284222900Snp * Otherwise, we are in defer mode, and we are at 285222900Snp * cancel point, tell kernel to not block the current 286222900Snp * thread on next cancelable system call. 287222900Snp * 288222900Snp * There are three cases we should call thr_wake() to 289222900Snp * turn on TDP_WAKEUP or send SIGCANCEL in kernel: 290222900Snp * 1) we are going to call a cancelable system call, 291222900Snp * non-zero cancel_point means we are already in 292222900Snp * cancelable state, next system call is cancelable. 293222900Snp * 2) because _thr_ast() may be called by 294222900Snp * THR_CRITICAL_LEAVE() which is used by rtld rwlock 295222900Snp * and any libthr internal locks, when rtld rwlock 296222900Snp * is used, it is mostly caused by an unresolved PLT. 297222900Snp * Those routines may clear the TDP_WAKEUP flag by 298222900Snp * invoking some system calls, in those cases, we 299222900Snp * also should reenable the flag. 300222900Snp * 3) thread is in sigsuspend(), and the syscall insists 301222900Snp * on getting a signal before it agrees to return. 302222900Snp */ 303222900Snp if (curthread->cancel_point) { 304222900Snp if (curthread->in_sigsuspend && ucp) { 305222900Snp SIGADDSET(ucp->uc_sigmask, SIGCANCEL); 306222900Snp curthread->unblock_sigcancel = 1; 307222900Snp _thr_send_sig(curthread, SIGCANCEL); 308222900Snp } else 309222900Snp thr_wake(curthread->tid); 310222900Snp } else if (curthread->cancel_async) { 311222900Snp /* 312222900Snp * asynchronous cancellation mode, act upon 313222900Snp * immediately. 314222900Snp */ 315222900Snp _pthread_exit_mask(PTHREAD_CANCELED, 316222900Snp ucp? &ucp->uc_sigmask : NULL); 317222900Snp } 318222900Snp} 319222900Snp 320222900Snpstatic void 321222900Snpcheck_deferred_signal(struct pthread *curthread) 322222900Snp{ 323222900Snp ucontext_t *uc; 324222900Snp struct sigaction act; 325222900Snp siginfo_t info; 326222900Snp int uc_len; 327222900Snp 328222900Snp if (__predict_true(curthread->deferred_siginfo.si_signo == 0 || 329222900Snp curthread->deferred_run)) 330222900Snp return; 331222900Snp 332222900Snp curthread->deferred_run = 1; 333222900Snp uc_len = __getcontextx_size(); 334222900Snp uc = alloca(uc_len); 335222900Snp getcontext(uc); 336222900Snp if (curthread->deferred_siginfo.si_signo == 0) { 337222900Snp curthread->deferred_run = 0; 338222900Snp return; 339222900Snp } 340222900Snp __fillcontextx2((char *)uc); 341222900Snp act = curthread->deferred_sigact; 342222900Snp uc->uc_sigmask = curthread->deferred_sigmask; 343222900Snp memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t)); 344222900Snp /* remove signal */ 345222900Snp curthread->deferred_siginfo.si_signo = 0; 346222900Snp handle_signal(&act, info.si_signo, &info, uc); 347222900Snp} 348222900Snp 349222900Snpstatic void 350222900Snpcheck_suspend(struct pthread *curthread) 351222900Snp{ 352222900Snp uint32_t cycle; 353222900Snp 354222900Snp if (__predict_true((curthread->flags & 355222900Snp (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 356222900Snp != THR_FLAGS_NEED_SUSPEND)) 357222900Snp return; 358222900Snp if (curthread == _single_thread) 359222900Snp return; 360222900Snp if (curthread->force_exit) 361222900Snp return; 362222900Snp 363222900Snp /* 364222900Snp * Blocks SIGCANCEL which other threads must send. 365222900Snp */ 366222900Snp _thr_signal_block(curthread); 367222900Snp 368222900Snp /* 369222900Snp * Increase critical_count, here we don't use THR_LOCK/UNLOCK 370222900Snp * because we are leaf code, we don't want to recursively call 371222900Snp * ourself. 372222900Snp */ 373222900Snp curthread->critical_count++; 374222900Snp THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 375222900Snp while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 376222900Snp THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 377222900Snp curthread->cycle++; 378222900Snp cycle = curthread->cycle; 379222900Snp 380222900Snp /* Wake the thread suspending us. */ 381222900Snp _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 382222900Snp 383222900Snp /* 384222900Snp * if we are from pthread_exit, we don't want to 385222900Snp * suspend, just go and die. 386222900Snp */ 387222900Snp if (curthread->state == PS_DEAD) 388222900Snp break; 389222900Snp curthread->flags |= THR_FLAGS_SUSPENDED; 390222900Snp THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 391222900Snp _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0); 392222900Snp THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 393222900Snp curthread->flags &= ~THR_FLAGS_SUSPENDED; 394222900Snp } 395222900Snp THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 396222900Snp curthread->critical_count--; 397222900Snp 398222900Snp _thr_signal_unblock(curthread); 399222900Snp} 400222900Snp 401222900Snpvoid 402222900Snp_thr_signal_init(int dlopened) 403222900Snp{ 404222900Snp struct sigaction act, nact, oact; 405222900Snp struct usigaction *usa; 406222900Snp sigset_t oldset; 407222900Snp int sig, error; 408222900Snp 409222900Snp if (dlopened) { 410222900Snp __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 411222900Snp for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 412222900Snp if (sig == SIGCANCEL) 413222900Snp continue; 414222900Snp error = __sys_sigaction(sig, NULL, &oact); 415222900Snp if (error == -1 || oact.sa_handler == SIG_DFL || 416222900Snp oact.sa_handler == SIG_IGN) 417222900Snp continue; 418222900Snp usa = __libc_sigaction_slot(sig); 419222900Snp usa->sigact = oact; 420222900Snp nact = oact; 421222900Snp remove_thr_signals(&usa->sigact.sa_mask); 422222900Snp nact.sa_flags &= ~SA_NODEFER; 423222900Snp nact.sa_flags |= SA_SIGINFO; 424222900Snp nact.sa_sigaction = thr_sighandler; 425222900Snp nact.sa_mask = _thr_maskset; 426222900Snp (void)__sys_sigaction(sig, &nact, NULL); 427222900Snp } 428222900Snp __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 429222900Snp } 430222900Snp 431222900Snp /* Install SIGCANCEL handler. */ 432222900Snp SIGFILLSET(act.sa_mask); 433222900Snp act.sa_flags = SA_SIGINFO; 434222900Snp act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 435222900Snp __sys_sigaction(SIGCANCEL, &act, NULL); 436222900Snp 437222900Snp /* Unblock SIGCANCEL */ 438222900Snp SIGEMPTYSET(act.sa_mask); 439222900Snp SIGADDSET(act.sa_mask, SIGCANCEL); 440222900Snp __sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL); 441222900Snp} 442222900Snp 443222900Snpvoid 444222900Snp_thr_sigact_unload(struct dl_phdr_info *phdr_info) 445222900Snp{ 446222900Snp#if 0 447222900Snp struct pthread *curthread = _get_curthread(); 448222900Snp struct urwlock *rwlp; 449222900Snp struct sigaction *actp; 450222900Snp struct usigaction *usa; 451222900Snp struct sigaction kact; 452222900Snp void (*handler)(int); 453222900Snp int sig; 454222900Snp 455222900Snp _thr_signal_block(curthread); 456222900Snp for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 457222900Snp usa = __libc_sigaction_slot(sig); 458222900Snp actp = &usa->sigact; 459222900Snpretry: 460222900Snp handler = actp->sa_handler; 461222900Snp if (handler != SIG_DFL && handler != SIG_IGN && 462222900Snp __elf_phdr_match_addr(phdr_info, handler)) { 463222900Snp rwlp = &usa->lock; 464222900Snp _thr_rwl_wrlock(rwlp); 465222900Snp if (handler != actp->sa_handler) { 466222900Snp _thr_rwl_unlock(rwlp); 467222900Snp goto retry; 468222900Snp } 469222900Snp actp->sa_handler = SIG_DFL; 470222900Snp actp->sa_flags = SA_SIGINFO; 471222900Snp SIGEMPTYSET(actp->sa_mask); 472222900Snp if (__sys_sigaction(sig, NULL, &kact) == 0 && 473222900Snp kact.sa_handler != SIG_DFL && 474222900Snp kact.sa_handler != SIG_IGN) 475222900Snp __sys_sigaction(sig, actp, NULL); 476222900Snp _thr_rwl_unlock(rwlp); 477222900Snp } 478222900Snp } 479222900Snp _thr_signal_unblock(curthread); 480222900Snp#endif 481222900Snp} 482222900Snp 483222900Snpvoid 484222900Snp_thr_signal_prefork(void) 485222900Snp{ 486222900Snp int i; 487222900Snp 488222900Snp for (i = 1; i <= _SIG_MAXSIG; ++i) 489222900Snp _thr_rwl_rdlock(&__libc_sigaction_slot(i)->lock); 490222900Snp} 491222900Snp 492222900Snpvoid 493222900Snp_thr_signal_postfork(void) 494222900Snp{ 495222900Snp int i; 496222900Snp 497222900Snp for (i = 1; i <= _SIG_MAXSIG; ++i) 498222900Snp _thr_rwl_unlock(&__libc_sigaction_slot(i)->lock); 499222900Snp} 500222900Snp 501222900Snpvoid 502222900Snp_thr_signal_postfork_child(void) 503222900Snp{ 504222900Snp int i; 505222900Snp 506222900Snp for (i = 1; i <= _SIG_MAXSIG; ++i) { 507222900Snp bzero(&__libc_sigaction_slot(i) -> lock, 508222900Snp sizeof(struct urwlock)); 509222900Snp } 510222900Snp} 511222900Snp 512222900Snpvoid 513222900Snp_thr_signal_deinit(void) 514222900Snp{ 515222900Snp} 516222900Snp 517222900Snpint 518222900Snp__thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) 519222900Snp{ 520222900Snp struct sigaction newact, oldact, oldact2; 521222900Snp sigset_t oldset; 522222900Snp struct usigaction *usa; 523222900Snp int ret, err; 524222900Snp 525222900Snp if (!_SIG_VALID(sig) || sig == SIGCANCEL) { 526222900Snp errno = EINVAL; 527222900Snp return (-1); 528222900Snp } 529222900Snp 530222900Snp ret = 0; 531222900Snp err = 0; 532222900Snp usa = __libc_sigaction_slot(sig); 533222900Snp 534222900Snp __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 535222900Snp _thr_rwl_wrlock(&usa->lock); 536222900Snp 537222900Snp if (act != NULL) { 538222900Snp oldact2 = usa->sigact; 539222900Snp newact = *act; 540222900Snp 541222900Snp /* 542222900Snp * if a new sig handler is SIG_DFL or SIG_IGN, 543222900Snp * don't remove old handler from __libc_sigact[], 544222900Snp * so deferred signals still can use the handlers, 545222900Snp * multiple threads invoking sigaction itself is 546222900Snp * a race condition, so it is not a problem. 547222900Snp */ 548222900Snp if (newact.sa_handler != SIG_DFL && 549222900Snp newact.sa_handler != SIG_IGN) { 550222900Snp usa->sigact = newact; 551222900Snp remove_thr_signals(&usa->sigact.sa_mask); 552222900Snp newact.sa_flags &= ~SA_NODEFER; 553222900Snp newact.sa_flags |= SA_SIGINFO; 554222900Snp newact.sa_sigaction = thr_sighandler; 555222900Snp newact.sa_mask = _thr_maskset; /* mask all signals */ 556222900Snp } 557222900Snp ret = __sys_sigaction(sig, &newact, &oldact); 558222900Snp if (ret == -1) { 559222900Snp err = errno; 560222900Snp usa->sigact = oldact2; 561222900Snp } 562222900Snp } else if (oact != NULL) { 563222900Snp ret = __sys_sigaction(sig, NULL, &oldact); 564222900Snp err = errno; 565222900Snp } 566222900Snp 567222900Snp if (oldact.sa_handler != SIG_DFL && oldact.sa_handler != SIG_IGN) { 568222900Snp if (act != NULL) 569222900Snp oldact = oldact2; 570222900Snp else if (oact != NULL) 571222900Snp oldact = usa->sigact; 572222900Snp } 573222900Snp 574222900Snp _thr_rwl_unlock(&usa->lock); 575222900Snp __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 576222900Snp 577222900Snp if (ret == 0) { 578222900Snp if (oact != NULL) 579222900Snp *oact = oldact; 580222900Snp } else { 581222900Snp errno = err; 582222900Snp } 583222900Snp return (ret); 584222900Snp} 585222900Snp 586222900Snpint 587222900Snp__thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset) 588222900Snp{ 589222900Snp const sigset_t *p = set; 590222900Snp sigset_t newset; 591222900Snp 592222900Snp if (how != SIG_UNBLOCK) { 593222900Snp if (set != NULL) { 594222900Snp newset = *set; 595222900Snp SIGDELSET(newset, SIGCANCEL); 596222900Snp p = &newset; 597222900Snp } 598222900Snp } 599222900Snp return (__sys_sigprocmask(how, p, oset)); 600222900Snp} 601222900Snp 602222900Snp__weak_reference(_pthread_sigmask, pthread_sigmask); 603222900Snp 604222900Snpint 605222900Snp_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 606222900Snp{ 607222900Snp 608222900Snp if (__thr_sigprocmask(how, set, oset)) 609222900Snp return (errno); 610222900Snp return (0); 611222900Snp} 612222900Snp 613222900Snpint 614222900Snp_sigsuspend(const sigset_t * set) 615222900Snp{ 616222900Snp sigset_t newset; 617222900Snp 618222900Snp return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset))); 619222900Snp} 620222900Snp 621222900Snpint 622222900Snp__thr_sigsuspend(const sigset_t * set) 623222900Snp{ 624222900Snp struct pthread *curthread; 625222900Snp sigset_t newset; 626222900Snp int ret, old; 627222900Snp 628222900Snp curthread = _get_curthread(); 629222900Snp 630222900Snp old = curthread->in_sigsuspend; 631222900Snp curthread->in_sigsuspend = 1; 632222900Snp _thr_cancel_enter(curthread); 633222900Snp ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); 634222900Snp _thr_cancel_leave(curthread, 1); 635222900Snp curthread->in_sigsuspend = old; 636222900Snp if (curthread->unblock_sigcancel) { 637222900Snp curthread->unblock_sigcancel = 0; 638222900Snp SIGEMPTYSET(newset); 639222900Snp SIGADDSET(newset, SIGCANCEL); 640222900Snp __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL); 641222900Snp } 642222900Snp 643222900Snp return (ret); 644222900Snp} 645222900Snp 646222900Snpint 647222900Snp_sigtimedwait(const sigset_t *set, siginfo_t *info, 648222900Snp const struct timespec * timeout) 649222900Snp{ 650222900Snp sigset_t newset; 651222900Snp 652222900Snp return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 653222900Snp timeout)); 654222900Snp} 655222900Snp 656222900Snp/* 657222900Snp * Cancellation behavior: 658222900Snp * Thread may be canceled at start, if thread got signal, 659222900Snp * it is not canceled. 660222900Snp */ 661222900Snpint 662222900Snp__thr_sigtimedwait(const sigset_t *set, siginfo_t *info, 663222900Snp const struct timespec * timeout) 664222900Snp{ 665222900Snp struct pthread *curthread = _get_curthread(); 666222900Snp sigset_t newset; 667222900Snp int ret; 668222900Snp 669222900Snp _thr_cancel_enter(curthread); 670222900Snp ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 671222900Snp timeout); 672222900Snp _thr_cancel_leave(curthread, (ret == -1)); 673222900Snp return (ret); 674222900Snp} 675222900Snp 676222900Snpint 677222900Snp_sigwaitinfo(const sigset_t *set, siginfo_t *info) 678222900Snp{ 679222900Snp sigset_t newset; 680222900Snp 681222900Snp return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info)); 682222900Snp} 683222900Snp 684222900Snp/* 685222900Snp * Cancellation behavior: 686222900Snp * Thread may be canceled at start, if thread got signal, 687222900Snp * it is not canceled. 688222900Snp */ 689222900Snpint 690222900Snp__thr_sigwaitinfo(const sigset_t *set, siginfo_t *info) 691222900Snp{ 692222900Snp struct pthread *curthread = _get_curthread(); 693222900Snp sigset_t newset; 694222900Snp int ret; 695222900Snp 696222900Snp _thr_cancel_enter(curthread); 697222900Snp ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info); 698222900Snp _thr_cancel_leave(curthread, ret == -1); 699222900Snp return (ret); 700222900Snp} 701222900Snp 702222900Snpint 703222900Snp_sigwait(const sigset_t *set, int *sig) 704222900Snp{ 705222900Snp sigset_t newset; 706222900Snp 707222900Snp return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig)); 708222900Snp} 709222900Snp 710222900Snp/* 711222900Snp * Cancellation behavior: 712222900Snp * Thread may be canceled at start, if thread got signal, 713222900Snp * it is not canceled. 714222900Snp */ 715222900Snpint 716222900Snp__thr_sigwait(const sigset_t *set, int *sig) 717222900Snp{ 718222900Snp struct pthread *curthread = _get_curthread(); 719222900Snp sigset_t newset; 720222900Snp int ret; 721222900Snp 722222900Snp do { 723222900Snp _thr_cancel_enter(curthread); 724222900Snp ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig); 725222900Snp _thr_cancel_leave(curthread, (ret != 0)); 726222900Snp } while (ret == EINTR); 727222900Snp return (ret); 728222900Snp} 729222900Snp 730222900Snpint 731222900Snp__thr_setcontext(const ucontext_t *ucp) 732222900Snp{ 733222900Snp ucontext_t uc; 734222900Snp 735222900Snp if (ucp == NULL) { 736222900Snp errno = EINVAL; 737222900Snp return (-1); 738222900Snp } 739222900Snp if (!SIGISMEMBER(uc.uc_sigmask, SIGCANCEL)) 740222900Snp return __sys_setcontext(ucp); 741222900Snp (void) memcpy(&uc, ucp, sizeof(uc)); 742222900Snp SIGDELSET(uc.uc_sigmask, SIGCANCEL); 743222900Snp return (__sys_setcontext(&uc)); 744222900Snp} 745222900Snp 746222900Snpint 747222900Snp__thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 748222900Snp{ 749222900Snp ucontext_t uc; 750222900Snp 751222900Snp if (oucp == NULL || ucp == NULL) { 752222900Snp errno = EINVAL; 753222900Snp return (-1); 754222900Snp } 755222900Snp if (SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) { 756222900Snp (void) memcpy(&uc, ucp, sizeof(uc)); 757222900Snp SIGDELSET(uc.uc_sigmask, SIGCANCEL); 758222900Snp ucp = &uc; 759222900Snp } 760222900Snp return (__sys_swapcontext(oucp, ucp)); 761222900Snp} 762222900Snp