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