xref: /freebsd/lib/libthr/thread/thr_sig.c (revision ecf4106237505fa9459ae871793b754334989c17)
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