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 "namespace.h" 30 #include <sys/param.h> 31 #include <sys/auxv.h> 32 #include <sys/elf.h> 33 #include <sys/signalvar.h> 34 #include <sys/syscall.h> 35 #include <signal.h> 36 #include <errno.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <pthread.h> 40 #include <pthread_np.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 void 168 pthread_signals_block_np(void) 169 { 170 struct pthread *curthread; 171 172 curthread = _get_curthread(); 173 _thr_signal_block(curthread); 174 } 175 176 void 177 pthread_signals_unblock_np(void) 178 { 179 struct pthread *curthread; 180 181 curthread = _get_curthread(); 182 _thr_signal_unblock(curthread); 183 } 184 185 int 186 _thr_send_sig(struct pthread *thread, int sig) 187 { 188 return thr_kill(thread->tid, sig); 189 } 190 191 static inline void 192 remove_thr_signals(sigset_t *set) 193 { 194 if (SIGISMEMBER(*set, SIGCANCEL)) 195 SIGDELSET(*set, SIGCANCEL); 196 } 197 198 static const sigset_t * 199 thr_remove_thr_signals(const sigset_t *set, sigset_t *newset) 200 { 201 *newset = *set; 202 remove_thr_signals(newset); 203 return (newset); 204 } 205 206 static void 207 sigcancel_handler(int sig __unused, siginfo_t *info __unused, ucontext_t *ucp) 208 { 209 struct pthread *curthread = _get_curthread(); 210 int err; 211 212 if (THR_IN_CRITICAL(curthread)) 213 return; 214 err = errno; 215 check_suspend(curthread); 216 check_cancel(curthread, ucp); 217 errno = err; 218 } 219 220 typedef void (*ohandler)(int sig, int code, struct sigcontext *scp, 221 char *addr, __sighandler_t *catcher); 222 223 /* 224 * The signal handler wrapper is entered with all signal masked. 225 */ 226 static void 227 thr_sighandler(int sig, siginfo_t *info, void *_ucp) 228 { 229 struct pthread *curthread; 230 ucontext_t *ucp; 231 struct sigaction act; 232 struct usigaction *usa; 233 int err; 234 235 err = errno; 236 curthread = _get_curthread(); 237 ucp = _ucp; 238 usa = __libc_sigaction_slot(sig); 239 _thr_rwl_rdlock(&usa->lock); 240 act = usa->sigact; 241 _thr_rwl_unlock(&usa->lock); 242 errno = err; 243 curthread->deferred_run = 0; 244 245 /* 246 * if a thread is in critical region, for example it holds low level locks, 247 * try to defer the signal processing, however if the signal is synchronous 248 * signal, it means a bad thing has happened, this is a programming error, 249 * resuming fault point can not help anything (normally causes deadloop), 250 * so here we let user code handle it immediately. 251 */ 252 if (THR_IN_CRITICAL(curthread) && SIGISMEMBER(_thr_deferset, sig)) { 253 memcpy(&curthread->deferred_sigact, &act, sizeof(struct sigaction)); 254 memcpy(&curthread->deferred_siginfo, info, sizeof(siginfo_t)); 255 curthread->deferred_sigmask = ucp->uc_sigmask; 256 /* mask all signals, we will restore it later. */ 257 ucp->uc_sigmask = _thr_deferset; 258 return; 259 } 260 261 handle_signal(&act, sig, info, ucp); 262 } 263 264 static void 265 handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp) 266 { 267 struct pthread *curthread = _get_curthread(); 268 __siginfohandler_t *sigfunc; 269 int cancel_point; 270 int cancel_async; 271 int cancel_enable; 272 int in_sigsuspend; 273 int err; 274 275 /* add previous level mask */ 276 SIGSETOR(actp->sa_mask, ucp->uc_sigmask); 277 278 /* add this signal's mask */ 279 if (!(actp->sa_flags & SA_NODEFER)) 280 SIGADDSET(actp->sa_mask, sig); 281 282 in_sigsuspend = curthread->in_sigsuspend; 283 curthread->in_sigsuspend = 0; 284 285 /* 286 * If thread is in deferred cancellation mode, disable cancellation 287 * in signal handler. 288 * If user signal handler calls a cancellation point function, e.g, 289 * it calls write() to write data to file, because write() is a 290 * cancellation point, the thread is immediately cancelled if 291 * cancellation is pending, to avoid this problem while thread is in 292 * deferring mode, cancellation is temporarily disabled. 293 */ 294 cancel_point = curthread->cancel_point; 295 cancel_async = curthread->cancel_async; 296 cancel_enable = curthread->cancel_enable; 297 curthread->cancel_point = 0; 298 if (!cancel_async) 299 curthread->cancel_enable = 0; 300 301 /* restore correct mask before calling user handler */ 302 __sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL); 303 304 sigfunc = actp->sa_sigaction; 305 306 /* 307 * We have already reset cancellation point flags, so if user's code 308 * longjmp()s out of its signal handler, wish its jmpbuf was set 309 * outside of a cancellation point, in most cases, this would be 310 * true. However, there is no way to save cancel_enable in jmpbuf, 311 * so after setjmps() returns once more, the user code may need to 312 * re-set cancel_enable flag by calling pthread_setcancelstate(). 313 */ 314 if ((actp->sa_flags & SA_SIGINFO) != 0) { 315 sigfunc(sig, info, ucp); 316 } else { 317 ((ohandler)sigfunc)(sig, info->si_code, 318 (struct sigcontext *)ucp, info->si_addr, 319 (__sighandler_t *)sigfunc); 320 } 321 err = errno; 322 323 curthread->in_sigsuspend = in_sigsuspend; 324 curthread->cancel_point = cancel_point; 325 curthread->cancel_enable = cancel_enable; 326 327 SIGDELSET(ucp->uc_sigmask, SIGCANCEL); 328 329 /* reschedule cancellation */ 330 check_cancel(curthread, ucp); 331 errno = err; 332 } 333 334 void 335 _thr_ast(struct pthread *curthread) 336 { 337 338 if (!THR_IN_CRITICAL(curthread)) { 339 check_deferred_signal(curthread); 340 check_suspend(curthread); 341 check_cancel(curthread, NULL); 342 } 343 } 344 345 /* reschedule cancellation */ 346 static void 347 check_cancel(struct pthread *curthread, ucontext_t *ucp) 348 { 349 350 if (__predict_true(!curthread->cancel_pending || 351 !curthread->cancel_enable || curthread->no_cancel)) 352 return; 353 354 /* 355 * Otherwise, we are in defer mode, and we are at 356 * cancel point, tell kernel to not block the current 357 * thread on next cancelable system call. 358 * 359 * There are three cases we should call thr_wake() to 360 * turn on TDP_WAKEUP or send SIGCANCEL in kernel: 361 * 1) we are going to call a cancelable system call, 362 * non-zero cancel_point means we are already in 363 * cancelable state, next system call is cancelable. 364 * 2) because _thr_ast() may be called by 365 * THR_CRITICAL_LEAVE() which is used by rtld rwlock 366 * and any libthr internal locks, when rtld rwlock 367 * is used, it is mostly caused by an unresolved PLT. 368 * Those routines may clear the TDP_WAKEUP flag by 369 * invoking some system calls, in those cases, we 370 * also should reenable the flag. 371 * 3) thread is in sigsuspend(), and the syscall insists 372 * on getting a signal before it agrees to return. 373 */ 374 if (curthread->cancel_point) { 375 if (curthread->in_sigsuspend) { 376 if (ucp != NULL) { 377 SIGADDSET(ucp->uc_sigmask, SIGCANCEL); 378 curthread->unblock_sigcancel = 1; 379 } 380 _thr_send_sig(curthread, SIGCANCEL); 381 } else 382 thr_wake(curthread->tid); 383 } else if (curthread->cancel_async) { 384 /* 385 * asynchronous cancellation mode, act upon 386 * immediately. 387 */ 388 _pthread_exit_mask(PTHREAD_CANCELED, ucp != NULL ? 389 &ucp->uc_sigmask : NULL); 390 } 391 } 392 393 static void 394 check_deferred_signal(struct pthread *curthread) 395 { 396 ucontext_t *uc; 397 struct sigaction act; 398 siginfo_t info; 399 int uc_len; 400 401 if (__predict_true(curthread->deferred_siginfo.si_signo == 0 || 402 curthread->deferred_run)) 403 return; 404 405 curthread->deferred_run = 1; 406 uc_len = __getcontextx_size(); 407 uc = alloca(uc_len); 408 getcontext(uc); 409 if (curthread->deferred_siginfo.si_signo == 0) { 410 curthread->deferred_run = 0; 411 return; 412 } 413 __fillcontextx2((char *)uc); 414 act = curthread->deferred_sigact; 415 uc->uc_sigmask = curthread->deferred_sigmask; 416 memcpy(&info, &curthread->deferred_siginfo, sizeof(siginfo_t)); 417 /* remove signal */ 418 curthread->deferred_siginfo.si_signo = 0; 419 handle_signal(&act, info.si_signo, &info, uc); 420 syscall(SYS_sigreturn, uc); 421 } 422 423 static void 424 check_suspend(struct pthread *curthread) 425 { 426 uint32_t cycle; 427 428 if (__predict_true((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 429 THR_FLAGS_SUSPENDED)) != THR_FLAGS_NEED_SUSPEND)) 430 return; 431 if (curthread == _single_thread) 432 return; 433 if (curthread->force_exit) 434 return; 435 436 /* 437 * Blocks SIGCANCEL which other threads must send. 438 */ 439 _thr_signal_block(curthread); 440 441 /* 442 * Increase critical_count, here we don't use THR_LOCK/UNLOCK 443 * because we are leaf code, we don't want to recursively call 444 * ourself. 445 */ 446 curthread->critical_count++; 447 THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 448 while ((curthread->flags & THR_FLAGS_NEED_SUSPEND) != 0) { 449 curthread->cycle++; 450 cycle = curthread->cycle; 451 452 /* Wake the thread suspending us. */ 453 _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 454 455 /* 456 * if we are from pthread_exit, we don't want to 457 * suspend, just go and die. 458 */ 459 if (curthread->state == PS_DEAD) 460 break; 461 curthread->flags |= THR_FLAGS_SUSPENDED; 462 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 463 _thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0); 464 THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 465 } 466 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 467 curthread->critical_count--; 468 469 _thr_signal_unblock(curthread); 470 } 471 472 void 473 _thr_signal_init(int dlopened) 474 { 475 struct sigaction act, nact, oact; 476 struct usigaction *usa; 477 sigset_t oldset; 478 int sig, error; 479 480 if (dlopened) { 481 __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 482 for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 483 if (sig == SIGCANCEL) 484 continue; 485 error = __sys_sigaction(sig, NULL, &oact); 486 if (error == -1 || oact.sa_handler == SIG_DFL || 487 oact.sa_handler == SIG_IGN) 488 continue; 489 usa = __libc_sigaction_slot(sig); 490 usa->sigact = oact; 491 nact = oact; 492 remove_thr_signals(&usa->sigact.sa_mask); 493 nact.sa_flags &= ~SA_NODEFER; 494 nact.sa_flags |= SA_SIGINFO; 495 nact.sa_sigaction = thr_sighandler; 496 nact.sa_mask = _thr_maskset; 497 (void)__sys_sigaction(sig, &nact, NULL); 498 } 499 __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 500 } 501 502 /* Install SIGCANCEL handler. */ 503 SIGFILLSET(act.sa_mask); 504 act.sa_flags = SA_SIGINFO; 505 act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 506 __sys_sigaction(SIGCANCEL, &act, NULL); 507 508 /* Unblock SIGCANCEL */ 509 SIGEMPTYSET(act.sa_mask); 510 SIGADDSET(act.sa_mask, SIGCANCEL); 511 __sys_sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL); 512 } 513 514 void 515 _thr_sigact_unload(struct dl_phdr_info *phdr_info __unused) 516 { 517 #if 0 518 struct pthread *curthread = _get_curthread(); 519 struct urwlock *rwlp; 520 struct sigaction *actp; 521 struct usigaction *usa; 522 struct sigaction kact; 523 void (*handler)(int); 524 int sig; 525 526 _thr_signal_block(curthread); 527 for (sig = 1; sig <= _SIG_MAXSIG; sig++) { 528 usa = __libc_sigaction_slot(sig); 529 actp = &usa->sigact; 530 retry: 531 handler = actp->sa_handler; 532 if (handler != SIG_DFL && handler != SIG_IGN && 533 __elf_phdr_match_addr(phdr_info, handler)) { 534 rwlp = &usa->lock; 535 _thr_rwl_wrlock(rwlp); 536 if (handler != actp->sa_handler) { 537 _thr_rwl_unlock(rwlp); 538 goto retry; 539 } 540 actp->sa_handler = SIG_DFL; 541 actp->sa_flags = SA_SIGINFO; 542 SIGEMPTYSET(actp->sa_mask); 543 if (__sys_sigaction(sig, NULL, &kact) == 0 && 544 kact.sa_handler != SIG_DFL && 545 kact.sa_handler != SIG_IGN) 546 __sys_sigaction(sig, actp, NULL); 547 _thr_rwl_unlock(rwlp); 548 } 549 } 550 _thr_signal_unblock(curthread); 551 #endif 552 } 553 554 void 555 _thr_signal_prefork(void) 556 { 557 int i; 558 559 for (i = 1; i <= _SIG_MAXSIG; ++i) 560 _thr_rwl_rdlock(&__libc_sigaction_slot(i)->lock); 561 } 562 563 void 564 _thr_signal_postfork(void) 565 { 566 int i; 567 568 for (i = 1; i <= _SIG_MAXSIG; ++i) 569 _thr_rwl_unlock(&__libc_sigaction_slot(i)->lock); 570 } 571 572 void 573 _thr_signal_postfork_child(void) 574 { 575 int i; 576 577 for (i = 1; i <= _SIG_MAXSIG; ++i) { 578 bzero(&__libc_sigaction_slot(i) -> lock, 579 sizeof(struct urwlock)); 580 } 581 } 582 583 void 584 _thr_signal_deinit(void) 585 { 586 } 587 588 int 589 __thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) 590 { 591 struct sigaction newact, oldact, oldact2; 592 sigset_t oldset; 593 struct usigaction *usa; 594 int ret, err; 595 596 if (!_SIG_VALID(sig) || sig == SIGCANCEL) { 597 errno = EINVAL; 598 return (-1); 599 } 600 601 ret = 0; 602 err = 0; 603 usa = __libc_sigaction_slot(sig); 604 605 __sys_sigprocmask(SIG_SETMASK, &_thr_maskset, &oldset); 606 _thr_rwl_wrlock(&usa->lock); 607 608 if (act != NULL) { 609 oldact2 = usa->sigact; 610 newact = *act; 611 612 /* 613 * if a new sig handler is SIG_DFL or SIG_IGN, 614 * don't remove old handler from __libc_sigact[], 615 * so deferred signals still can use the handlers, 616 * multiple threads invoking sigaction itself is 617 * a race condition, so it is not a problem. 618 */ 619 if (newact.sa_handler != SIG_DFL && 620 newact.sa_handler != SIG_IGN) { 621 usa->sigact = newact; 622 remove_thr_signals(&usa->sigact.sa_mask); 623 newact.sa_flags &= ~SA_NODEFER; 624 newact.sa_flags |= SA_SIGINFO; 625 newact.sa_sigaction = thr_sighandler; 626 newact.sa_mask = _thr_maskset; /* mask all signals */ 627 } 628 ret = __sys_sigaction(sig, &newact, &oldact); 629 if (ret == -1) { 630 err = errno; 631 usa->sigact = oldact2; 632 } 633 } else if (oact != NULL) { 634 ret = __sys_sigaction(sig, NULL, &oldact); 635 err = errno; 636 } 637 638 if (oldact.sa_handler != SIG_DFL && oldact.sa_handler != SIG_IGN) { 639 if (act != NULL) 640 oldact = oldact2; 641 else if (oact != NULL) 642 oldact = usa->sigact; 643 } 644 645 _thr_rwl_unlock(&usa->lock); 646 __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); 647 648 if (ret == 0) { 649 if (oact != NULL) 650 *oact = oldact; 651 } else { 652 errno = err; 653 } 654 return (ret); 655 } 656 657 int 658 __thr_sigprocmask(int how, const sigset_t *set, sigset_t *oset) 659 { 660 const sigset_t *p = set; 661 sigset_t newset; 662 663 if (how != SIG_UNBLOCK) { 664 if (set != NULL) { 665 newset = *set; 666 SIGDELSET(newset, SIGCANCEL); 667 p = &newset; 668 } 669 } 670 return (__sys_sigprocmask(how, p, oset)); 671 } 672 673 __weak_reference(_thr_sigmask, pthread_sigmask); 674 __weak_reference(_thr_sigmask, _pthread_sigmask); 675 676 int 677 _thr_sigmask(int how, const sigset_t *set, sigset_t *oset) 678 { 679 680 if (__thr_sigprocmask(how, set, oset)) 681 return (errno); 682 return (0); 683 } 684 685 int 686 __thr_sigsuspend(const sigset_t *set) 687 { 688 struct pthread *curthread; 689 sigset_t newset; 690 int ret, old; 691 692 curthread = _get_curthread(); 693 694 old = curthread->in_sigsuspend; 695 curthread->in_sigsuspend = 1; 696 _thr_cancel_enter(curthread); 697 ret = __sys_sigsuspend(thr_remove_thr_signals(set, &newset)); 698 _thr_cancel_leave(curthread, 1); 699 curthread->in_sigsuspend = old; 700 if (curthread->unblock_sigcancel) { 701 curthread->unblock_sigcancel = 0; 702 SIGEMPTYSET(newset); 703 SIGADDSET(newset, SIGCANCEL); 704 __sys_sigprocmask(SIG_UNBLOCK, &newset, NULL); 705 } 706 707 return (ret); 708 } 709 710 int 711 _sigtimedwait(const sigset_t *set, siginfo_t *info, 712 const struct timespec *timeout) 713 { 714 sigset_t newset; 715 716 return (__sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 717 timeout)); 718 } 719 720 /* 721 * Cancellation behavior: 722 * Thread may be canceled at start, if thread got signal, 723 * it is not canceled. 724 */ 725 int 726 __thr_sigtimedwait(const sigset_t *set, siginfo_t *info, 727 const struct timespec *timeout) 728 { 729 struct pthread *curthread = _get_curthread(); 730 sigset_t newset; 731 int ret; 732 733 _thr_cancel_enter(curthread); 734 ret = __sys_sigtimedwait(thr_remove_thr_signals(set, &newset), info, 735 timeout); 736 _thr_cancel_leave(curthread, (ret == -1)); 737 return (ret); 738 } 739 740 int 741 _sigwaitinfo(const sigset_t *set, siginfo_t *info) 742 { 743 sigset_t newset; 744 745 return (__sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info)); 746 } 747 748 /* 749 * Cancellation behavior: 750 * Thread may be canceled at start, if thread got signal, 751 * it is not canceled. 752 */ 753 int 754 __thr_sigwaitinfo(const sigset_t *set, siginfo_t *info) 755 { 756 struct pthread *curthread = _get_curthread(); 757 sigset_t newset; 758 int ret; 759 760 _thr_cancel_enter(curthread); 761 ret = __sys_sigwaitinfo(thr_remove_thr_signals(set, &newset), info); 762 _thr_cancel_leave(curthread, ret == -1); 763 return (ret); 764 } 765 766 int 767 _sigwait(const sigset_t *set, int *sig) 768 { 769 sigset_t newset; 770 771 return (__sys_sigwait(thr_remove_thr_signals(set, &newset), sig)); 772 } 773 774 /* 775 * Cancellation behavior: 776 * Thread may be canceled at start, if thread got signal, 777 * it is not canceled. 778 */ 779 int 780 __thr_sigwait(const sigset_t *set, int *sig) 781 { 782 struct pthread *curthread = _get_curthread(); 783 sigset_t newset; 784 int ret; 785 786 do { 787 _thr_cancel_enter(curthread); 788 ret = __sys_sigwait(thr_remove_thr_signals(set, &newset), sig); 789 _thr_cancel_leave(curthread, (ret != 0)); 790 } while (ret == EINTR); 791 return (ret); 792 } 793 794 int 795 __thr_setcontext(const ucontext_t *ucp) 796 { 797 ucontext_t uc; 798 799 if (ucp == NULL) { 800 errno = EINVAL; 801 return (-1); 802 } 803 if (!SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) 804 return (__sys_setcontext(ucp)); 805 (void) memcpy(&uc, ucp, sizeof(uc)); 806 SIGDELSET(uc.uc_sigmask, SIGCANCEL); 807 return (__sys_setcontext(&uc)); 808 } 809 810 int 811 __thr_swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 812 { 813 ucontext_t uc; 814 815 if (oucp == NULL || ucp == NULL) { 816 errno = EINVAL; 817 return (-1); 818 } 819 if (SIGISMEMBER(ucp->uc_sigmask, SIGCANCEL)) { 820 (void) memcpy(&uc, ucp, sizeof(uc)); 821 SIGDELSET(uc.uc_sigmask, SIGCANCEL); 822 ucp = &uc; 823 } 824 return (__sys_swapcontext(oucp, ucp)); 825 } 826