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