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