1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #include "namespace.h" 31 #include <sys/param.h> 32 #include <sys/auxv.h> 33 #include <sys/elf.h> 34 #include <sys/signalvar.h> 35 #include <sys/syscall.h> 36 #include <signal.h> 37 #include <errno.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <pthread.h> 41 #include "un-namespace.h" 42 #include "libc_private.h" 43 44 #include "libc_private.h" 45 #include "thr_private.h" 46 47 /* #define DEBUG_SIGNAL */ 48 #ifdef DEBUG_SIGNAL 49 #define DBG_MSG stdout_debug 50 #else 51 #define DBG_MSG(x...) 52 #endif 53 54 struct usigaction { 55 struct sigaction sigact; 56 struct urwlock lock; 57 }; 58 59 static struct usigaction _thr_sigact[_SIG_MAXSIG]; 60 61 static inline struct usigaction * 62 __libc_sigaction_slot(int signo) 63 { 64 65 return (&_thr_sigact[signo - 1]); 66 } 67 68 static void thr_sighandler(int, siginfo_t *, void *); 69 static void handle_signal(struct sigaction *, int, siginfo_t *, ucontext_t *); 70 static void check_deferred_signal(struct pthread *); 71 static void check_suspend(struct pthread *); 72 static void check_cancel(struct pthread *curthread, ucontext_t *ucp); 73 74 int _sigtimedwait(const sigset_t *set, siginfo_t *info, 75 const struct timespec * timeout); 76 int _sigwaitinfo(const sigset_t *set, siginfo_t *info); 77 int _sigwait(const sigset_t *set, int *sig); 78 int _setcontext(const ucontext_t *); 79 int _swapcontext(ucontext_t *, const ucontext_t *); 80 81 static const sigset_t _thr_deferset={{ 82 0xffffffff & ~(_SIG_BIT(SIGBUS)|_SIG_BIT(SIGILL)|_SIG_BIT(SIGFPE)| 83 _SIG_BIT(SIGSEGV)|_SIG_BIT(SIGTRAP)|_SIG_BIT(SIGSYS)), 84 0xffffffff, 85 0xffffffff, 86 0xffffffff}}; 87 88 static const sigset_t _thr_maskset={{ 89 0xffffffff, 90 0xffffffff, 91 0xffffffff, 92 0xffffffff}}; 93 94 static void 95 thr_signal_block_slow(struct pthread *curthread) 96 { 97 if (curthread->sigblock > 0) { 98 curthread->sigblock++; 99 return; 100 } 101 __sys_sigprocmask(SIG_BLOCK, &_thr_maskset, &curthread->sigmask); 102 curthread->sigblock++; 103 } 104 105 static void 106 thr_signal_unblock_slow(struct pthread *curthread) 107 { 108 if (--curthread->sigblock == 0) 109 __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 110 } 111 112 static void 113 thr_signal_block_fast(struct pthread *curthread) 114 { 115 atomic_add_32(&curthread->fsigblock, SIGFASTBLOCK_INC); 116 } 117 118 static void 119 thr_signal_unblock_fast(struct pthread *curthread) 120 { 121 uint32_t oldval; 122 123 oldval = atomic_fetchadd_32(&curthread->fsigblock, -SIGFASTBLOCK_INC); 124 if (oldval == (SIGFASTBLOCK_PEND | SIGFASTBLOCK_INC)) 125 __sys_sigfastblock(SIGFASTBLOCK_UNBLOCK, NULL); 126 } 127 128 static bool fast_sigblock; 129 130 void 131 _thr_signal_block(struct pthread *curthread) 132 { 133 if (fast_sigblock) 134 thr_signal_block_fast(curthread); 135 else 136 thr_signal_block_slow(curthread); 137 } 138 139 void 140 _thr_signal_unblock(struct pthread *curthread) 141 { 142 if (fast_sigblock) 143 thr_signal_unblock_fast(curthread); 144 else 145 thr_signal_unblock_slow(curthread); 146 } 147 148 void 149 _thr_signal_block_check_fast(void) 150 { 151 int bsdflags, error; 152 153 error = elf_aux_info(AT_BSDFLAGS, &bsdflags, sizeof(bsdflags)); 154 if (error != 0) 155 return; 156 fast_sigblock = (bsdflags & ELF_BSDF_SIGFASTBLK) != 0; 157 } 158 159 void 160 _thr_signal_block_setup(struct pthread *curthread) 161 { 162 if (!fast_sigblock) 163 return; 164 __sys_sigfastblock(SIGFASTBLOCK_SETPTR, &curthread->fsigblock); 165 } 166 167 int 168 _thr_send_sig(struct pthread *thread, int sig) 169 { 170 return thr_kill(thread->tid, sig); 171 } 172 173 static inline void 174 remove_thr_signals(sigset_t *set) 175 { 176 if (SIGISMEMBER(*set, SIGCANCEL)) 177 SIGDELSET(*set, SIGCANCEL); 178 } 179 180 static const sigset_t * 181 thr_remove_thr_signals(const sigset_t *set, sigset_t *newset) 182 { 183 *newset = *set; 184 remove_thr_signals(newset); 185 return (newset); 186 } 187 188 static void 189 sigcancel_handler(int sig __unused, 190 siginfo_t *info __unused, ucontext_t *ucp) 191 { 192 struct pthread *curthread = _get_curthread(); 193 int err; 194 195 if (THR_IN_CRITICAL(curthread)) 196 return; 197 err = errno; 198 check_suspend(curthread); 199 check_cancel(curthread, ucp); 200 errno = err; 201 } 202 203 typedef void (*ohandler)(int sig, int code, struct sigcontext *scp, 204 char *addr, __sighandler_t *catcher); 205 206 /* 207 * The signal handler wrapper is entered with all signal masked. 208 */ 209 static void 210 thr_sighandler(int sig, siginfo_t *info, void *_ucp) 211 { 212 struct pthread *curthread; 213 ucontext_t *ucp; 214 struct sigaction act; 215 struct usigaction *usa; 216 int err; 217 218 err = errno; 219 curthread = _get_curthread(); 220 ucp = _ucp; 221 usa = __libc_sigaction_slot(sig); 222 _thr_rwl_rdlock(&usa->lock); 223 act = usa->sigact; 224 _thr_rwl_unlock(&usa->lock); 225 errno = err; 226 curthread->deferred_run = 0; 227 228 /* 229 * if a thread is in critical region, for example it holds low level locks, 230 * try to defer the signal processing, however if the signal is synchronous 231 * signal, it means a bad thing has happened, this is a programming error, 232 * resuming fault point can not help anything (normally causes deadloop), 233 * so here we let user code handle it immediately. 234 */ 235 if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) { 236 memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction)); 237 memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t)); 238 curthread->deferred_sigmask = ucp->uc_sigmask; 239 /* mask all signals, we will restore it later. */ 240 ucp->uc_sigmask = _thr_deferset; 241 return; 242 } 243 244 handle_signal(&act, sig, info, ucp); 245 } 246 247 static void 248 handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) 249 { 250 struct pthread *curthread = _get_curthread(); 251 ucontext_t uc2; 252 __siginfohandler_t *sigfunc; 253 int cancel_point; 254 int cancel_async; 255 int cancel_enable; 256 int in_sigsuspend; 257 int err; 258 259 /* add previous level mask */ 260 SIGSETOR(actp->sa_mask, ucp->uc_sigmask); 261 262 /* add this signal's mask */ 263 if (!(actp->sa_flags & SA_NODEFER)) 264 SIGADDSET(actp->sa_mask, sig); 265 266 in_sigsuspend = curthread->in_sigsuspend; 267 curthread->in_sigsuspend = 0; 268 269 /* 270 * If thread is in deferred cancellation mode, disable cancellation 271 * in signal handler. 272 * If user signal handler calls a cancellation point function, e.g, 273 * it calls write() to write data to file, because write() is a 274 * cancellation point, the thread is immediately cancelled if 275 * cancellation is pending, to avoid this problem while thread is in 276 * deferring mode, cancellation is temporarily disabled. 277 */ 278 cancel_point = curthread->cancel_point; 279 cancel_async = curthread->cancel_async; 280 cancel_enable = curthread->cancel_enable; 281 curthread->cancel_point = 0; 282 if (!cancel_async) 283 curthread->cancel_enable = 0; 284 285 /* restore correct mask before calling user handler */ 286 __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL); 287 288 sigfunc = actp->sa_sigaction; 289 290 /* 291 * We have already reset cancellation point flags, so if user's code 292 * longjmp()s out of its signal handler, wish its jmpbuf was set 293 * outside of a cancellation point, in most cases, this would be 294 * true. However, there is no way to save cancel_enable in jmpbuf, 295 * so after setjmps() returns once more, the user code may need to 296 * re-set cancel_enable flag by calling pthread_setcancelstate(). 297 */ 298 if ((actp->sa_flags & SA_SIGINFO) != 0) { 299 sigfunc(sig, info, ucp); 300 } else { 301 ((ohandler)sigfunc)(sig, info->si_code, 302 (struct sigcontext *)ucp, info->si_addr, 303 (__sighandler_t *)sigfunc); 304 } 305 err = errno; 306 307 curthread->in_sigsuspend = in_sigsuspend; 308 curthread->cancel_point = cancel_point; 309 curthread->cancel_enable = cancel_enable; 310 311 memcpy(&uc2, ucp, sizeof(uc2)); 312 SIGDELSET(uc2.uc_sigmask, SIGCANCEL); 313 314 /* reschedule cancellation */ 315 check_cancel(curthread, &uc2); 316 errno = err; 317 syscall(SYS_sigreturn, &uc2); 318 } 319 320 void 321 _thr_ast(struct pthread *curthread) 322 { 323 324 if (!THR_IN_CRITICAL(curthread)) { 325 check_deferred_signal(curthread); 326 check_suspend(curthread); 327 check_cancel(curthread, NULL); 328 } 329 } 330 331 /* reschedule cancellation */ 332 static void 333 check_cancel(struct pthread *curthread, ucontext_t *ucp) 334 { 335 336 if (__predict_true(!curthread->cancel_pending || 337 !curthread->cancel_enable || curthread->no_cancel)) 338 return; 339 340 /* 341 * Otherwise, we are in defer mode, and we are at 342 * cancel point, tell kernel to not block the current 343 * thread on next cancelable system call. 344 * 345 * There are three cases we should call thr_wake() to 346 * turn on TDP_WAKEUP or send SIGCANCEL in kernel: 347 * 1) we are going to call a cancelable system call, 348 * non-zero cancel_point means we are already in 349 * cancelable state, next system call is cancelable. 350 * 2) because _thr_ast() may be called by 351 * THR_CRITICAL_LEAVE() which is used by rtld rwlock 352 * and any libthr internal locks, when rtld rwlock 353 * is used, it is mostly caused by an unresolved PLT. 354 * Those routines may clear the TDP_WAKEUP flag by 355 * invoking some system calls, in those cases, we 356 * also should reenable the flag. 357 * 3) thread is in sigsuspend(), and the syscall insists 358 * on getting a signal before it agrees to return. 359 */ 360 if (curthread->cancel_point) { 361 if (curthread->in_sigsuspend && ucp) { 362 SIGADDSET(ucp->uc_sigmask, SIGCANCEL); 363 curthread->unblock_sigcancel = 1; 364 _thr_send_sig(curthread, SIGCANCEL); 365 } else 366 thr_wake(curthread->tid); 367 } else if (curthread->cancel_async) { 368 /* 369 * asynchronous cancellation mode, act upon 370 * immediately. 371 */ 372 _pthread_exit_mask(PTHREAD_CANCELED, 373 ucp? &ucp->uc_sigmask : NULL); 374 } 375 } 376 377 static void 378 check_deferred_signal(struct pthread *curthread) 379 { 380 ucontext_t *uc; 381 struct sigaction act; 382 siginfo_t info; 383 int uc_len; 384 385 if (__predict_true(curthread->deferred_siginfo.si_signo == 0 || 386 curthread->deferred_run)) 387 return; 388 389 curthread->deferred_run = 1; 390 uc_len = __getcontextx_size(); 391 uc = alloca(uc_len); 392 getcontext(uc); 393 if (curthread->deferred_siginfo.si_signo == 0) { 394 curthread->deferred_run = 0; 395 return; 396 } 397 __fillcontextx2((char *)uc); 398 act = curthread->deferred_sigact; 399 uc->uc_sigmask = curthread->deferred_sigmask; 400 memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t)); 401 /* remove signal */ 402 curthread->deferred_siginfo.si_signo = 0; 403 handle_signal(&act, info.si_signo, &info, uc); 404 } 405 406 static void 407 check_suspend(struct pthread *curthread) 408 { 409 uint32_t cycle; 410 411 if (__predict_true((curthread->flags & 412 (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 413 != THR_FLAGS_NEED_SUSPEND)) 414 return; 415 if (curthread == _single_thread) 416 return; 417 if (curthread->force_exit) 418 return; 419 420 /* 421 * Blocks SIGCANCEL which other threads must send. 422 */ 423 _thr_signal_block(curthread); 424 425 /* 426 * Increase critical_count, here we don't use THR_LOCK/UNLOCK 427 * because we are leaf code, we don't want to recursively call 428 * ourself. 429 */ 430 curthread->critical_count++; 431 THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 432 while ((curthread->flags & THR_FLAGS_NEED_SUSPEND) != 0) { 433 curthread->cycle++; 434 cycle = curthread->cycle; 435 436 /* Wake the thread suspending us. */ 437 _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 438 439 /* 440 * if we are from pthread_exit, we don't want to 441 * suspend, just go and die. 442 */ 443 if (curthread->state == PS_DEAD) 444 break; 445 curthread->flags |= THR_FLAGS_SUSPENDED; 446 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 447 _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0); 448 THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 449 } 450 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 451 curthread->critical_count--; 452 453 _thr_signal_unblock(curthread); 454 } 455 456 void 457 _thr_signal_init(int dlopened) 458 { 459 struct sigaction act, nact, oact; 460 struct usigaction *usa; 461 sigset_t oldset; 462 int sig, error; 463 464 if (dlopened) { 465 __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 466 for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 467 if (sig == SIGCANCEL) 468 continue; 469 error = __sys_sigaction(sig, NULL, &oact); 470 if (error == -1 || oact.sa_handler == SIG_DFL || 471 oact.sa_handler == SIG_IGN) 472 continue; 473 usa = __libc_sigaction_slot(sig); 474 usa->sigact = oact; 475 nact = oact; 476 remove_thr_signals(&usa->sigact.sa_mask); 477 nact.sa_flags &= ~SA_NODEFER; 478 nact.sa_flags |= SA_SIGINFO; 479 nact.sa_sigaction = thr_sighandler; 480 nact.sa_mask = _thr_maskset; 481 (void)__sys_sigaction(sig, &nact, NULL); 482 } 483 __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 484 } 485 486 /* Install SIGCANCEL handler. */ 487 SIGFILLSET(act.sa_mask); 488 act.sa_flags = SA_SIGINFO; 489 act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 490 __sys_sigaction(SIGCANCEL, &act, NULL); 491 492 /* Unblock SIGCANCEL */ 493 SIGEMPTYSET(act.sa_mask); 494 SIGADDSET(act.sa_mask, SIGCANCEL); 495 __sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL); 496 } 497 498 void 499 _thr_sigact_unload(struct dl_phdr_info *phdr_info __unused) 500 { 501 #if 0 502 struct pthread *curthread = _get_curthread(); 503 struct urwlock *rwlp; 504 struct sigaction *actp; 505 struct usigaction *usa; 506 struct sigaction kact; 507 void (*handler)(int); 508 int sig; 509 510 _thr_signal_block(curthread); 511 for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 512 usa = __libc_sigaction_slot(sig); 513 actp = &usa->sigact; 514 retry: 515 handler = actp->sa_handler; 516 if (handler != SIG_DFL && handler != SIG_IGN && 517 __elf_phdr_match_addr(phdr_info, handler)) { 518 rwlp = &usa->lock; 519 _thr_rwl_wrlock(rwlp); 520 if (handler != actp->sa_handler) { 521 _thr_rwl_unlock(rwlp); 522 goto retry; 523 } 524 actp->sa_handler = SIG_DFL; 525 actp->sa_flags = SA_SIGINFO; 526 SIGEMPTYSET(actp->sa_mask); 527 if (__sys_sigaction(sig, NULL, &kact) == 0 && 528 kact.sa_handler != SIG_DFL && 529 kact.sa_handler != SIG_IGN) 530 __sys_sigaction(sig, actp, NULL); 531 _thr_rwl_unlock(rwlp); 532 } 533 } 534 _thr_signal_unblock(curthread); 535 #endif 536 } 537 538 void 539 _thr_signal_prefork(void) 540 { 541 int i; 542 543 for (i = 1; i <= _SIG_MAXSIG; ++i) 544 _thr_rwl_rdlock(&__libc_sigaction_slot(i)->lock); 545 } 546 547 void 548 _thr_signal_postfork(void) 549 { 550 int i; 551 552 for (i = 1; i <= _SIG_MAXSIG; ++i) 553 _thr_rwl_unlock(&__libc_sigaction_slot(i)->lock); 554 } 555 556 void 557 _thr_signal_postfork_child(void) 558 { 559 int i; 560 561 for (i = 1; i <= _SIG_MAXSIG; ++i) { 562 bzero(&__libc_sigaction_slot(i) -> lock, 563 sizeof(struct urwlock)); 564 } 565 } 566 567 void 568 _thr_signal_deinit(void) 569 { 570 } 571 572 int 573 __thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) 574 { 575 struct sigaction newact, oldact, oldact2; 576 sigset_t oldset; 577 struct usigaction *usa; 578 int ret, err; 579 580 if (!_SIG_VALID(sig) || sig == SIGCANCEL) { 581 errno = EINVAL; 582 return (-1); 583 } 584 585 ret = 0; 586 err = 0; 587 usa = __libc_sigaction_slot(sig); 588 589 __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 590 _thr_rwl_wrlock(&usa->lock); 591 592 if (act != NULL) { 593 oldact2 = usa->sigact; 594 newact = *act; 595 596 /* 597 * if a new sig handler is SIG_DFL or SIG_IGN, 598 * don't remove old handler from __libc_sigact[], 599 * so deferred signals still can use the handlers, 600 * multiple threads invoking sigaction itself is 601 * a race condition, so it is not a problem. 602 */ 603 if (newact.sa_handler != SIG_DFL && 604 newact.sa_handler != SIG_IGN) { 605 usa->sigact = newact; 606 remove_thr_signals(&usa->sigact.sa_mask); 607 newact.sa_flags &= ~SA_NODEFER; 608 newact.sa_flags |= SA_SIGINFO; 609 newact.sa_sigaction = thr_sighandler; 610 newact.sa_mask = _thr_maskset; /* mask all signals */ 611 } 612 ret = __sys_sigaction(sig, &newact, &oldact); 613 if (ret == -1) { 614 err = errno; 615 usa->sigact = oldact2; 616 } 617 } else if (oact != NULL) { 618 ret = __sys_sigaction(sig, NULL, &oldact); 619 err = errno; 620 } 621 622 if (oldact.sa_handler != SIG_DFL && oldact.sa_handler != SIG_IGN) { 623 if (act != NULL) 624 oldact = oldact2; 625 else if (oact != NULL) 626 oldact = usa->sigact; 627 } 628 629 _thr_rwl_unlock(&usa->lock); 630 __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 631 632 if (ret == 0) { 633 if (oact != NULL) 634 *oact = oldact; 635 } else { 636 errno = err; 637 } 638 return (ret); 639 } 640 641 int 642 __thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset) 643 { 644 const sigset_t *p = set; 645 sigset_t newset; 646 647 if (how != SIG_UNBLOCK) { 648 if (set != NULL) { 649 newset = *set; 650 SIGDELSET(newset, SIGCANCEL); 651 p = &newset; 652 } 653 } 654 return (__sys_sigprocmask(how, p, oset)); 655 } 656 657 __weak_reference(_thr_sigmask, pthread_sigmask); 658 __weak_reference(_thr_sigmask, _pthread_sigmask); 659 660 int 661 _thr_sigmask(int how, const sigset_t *set, sigset_t *oset) 662 { 663 664 if (__thr_sigprocmask(how, set, oset)) 665 return (errno); 666 return (0); 667 } 668 669 int 670 _sigsuspend(const sigset_t * set) 671 { 672 sigset_t newset; 673 674 return (__sys_sigsuspend(thr_remove_thr_signals(set, &newset))); 675 } 676 677 int 678 __thr_sigsuspend(const sigset_t * set) 679 { 680 struct pthread *curthread; 681 sigset_t newset; 682 int ret, old; 683 684 curthread = _get_curthread(); 685 686 old = curthread->in_sigsuspend; 687 curthread->in_sigsuspend = 1; 688 _thr_cancel_enter(curthread); 689 ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); 690 _thr_cancel_leave(curthread, 1); 691 curthread->in_sigsuspend = old; 692 if (curthread->unblock_sigcancel) { 693 curthread->unblock_sigcancel = 0; 694 SIGEMPTYSET(newset); 695 SIGADDSET(newset, SIGCANCEL); 696 __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL); 697 } 698 699 return (ret); 700 } 701 702 int 703 _sigtimedwait(const sigset_t *set, siginfo_t *info, 704 const struct timespec * timeout) 705 { 706 sigset_t newset; 707 708 return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 709 timeout)); 710 } 711 712 /* 713 * Cancellation behavior: 714 * Thread may be canceled at start, if thread got signal, 715 * it is not canceled. 716 */ 717 int 718 __thr_sigtimedwait(const sigset_t *set, siginfo_t *info, 719 const struct timespec * timeout) 720 { 721 struct pthread *curthread = _get_curthread(); 722 sigset_t newset; 723 int ret; 724 725 _thr_cancel_enter(curthread); 726 ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 727 timeout); 728 _thr_cancel_leave(curthread, (ret == -1)); 729 return (ret); 730 } 731 732 int 733 _sigwaitinfo(const sigset_t *set, siginfo_t *info) 734 { 735 sigset_t newset; 736 737 return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info)); 738 } 739 740 /* 741 * Cancellation behavior: 742 * Thread may be canceled at start, if thread got signal, 743 * it is not canceled. 744 */ 745 int 746 __thr_sigwaitinfo(const sigset_t *set, siginfo_t *info) 747 { 748 struct pthread *curthread = _get_curthread(); 749 sigset_t newset; 750 int ret; 751 752 _thr_cancel_enter(curthread); 753 ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info); 754 _thr_cancel_leave(curthread, ret == -1); 755 return (ret); 756 } 757 758 int 759 _sigwait(const sigset_t *set, int *sig) 760 { 761 sigset_t newset; 762 763 return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig)); 764 } 765 766 /* 767 * Cancellation behavior: 768 * Thread may be canceled at start, if thread got signal, 769 * it is not canceled. 770 */ 771 int 772 __thr_sigwait(const sigset_t *set, int *sig) 773 { 774 struct pthread *curthread = _get_curthread(); 775 sigset_t newset; 776 int ret; 777 778 do { 779 _thr_cancel_enter(curthread); 780 ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig); 781 _thr_cancel_leave(curthread, (ret != 0)); 782 } while (ret == EINTR); 783 return (ret); 784 } 785 786 int 787 __thr_setcontext(const ucontext_t *ucp) 788 { 789 ucontext_t uc; 790 791 if (ucp == NULL) { 792 errno = EINVAL; 793 return (-1); 794 } 795 if (!SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) 796 return (__sys_setcontext(ucp)); 797 (void) memcpy(&uc, ucp, sizeof(uc)); 798 SIGDELSET(uc.uc_sigmask, SIGCANCEL); 799 return (__sys_setcontext(&uc)); 800 } 801 802 int 803 __thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 804 { 805 ucontext_t uc; 806 807 if (oucp == NULL || ucp == NULL) { 808 errno = EINVAL; 809 return (-1); 810 } 811 if (SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) { 812 (void) memcpy(&uc, ucp, sizeof(uc)); 813 SIGDELSET(uc.uc_sigmask, SIGCANCEL); 814 ucp = &uc; 815 } 816 return (__sys_swapcontext(oucp, ucp)); 817 } 818