xref: /freebsd/lib/libthr/thread/thr_sig.c (revision 635f917a9d024248ee484721dd1d1c899c44e8d0)
1bb535300SJeff Roberson /*
2df2cf821SDavid Xu  * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
3bb535300SJeff Roberson  * All rights reserved.
4bb535300SJeff Roberson  *
5bb535300SJeff Roberson  * Redistribution and use in source and binary forms, with or without
6bb535300SJeff Roberson  * modification, are permitted provided that the following conditions
7bb535300SJeff Roberson  * are met:
8bb535300SJeff Roberson  * 1. Redistributions of source code must retain the above copyright
9df2cf821SDavid Xu  *    notice unmodified, this list of conditions, and the following
10df2cf821SDavid Xu  *    disclaimer.
11bb535300SJeff Roberson  * 2. Redistributions in binary form must reproduce the above copyright
12bb535300SJeff Roberson  *    notice, this list of conditions and the following disclaimer in the
13bb535300SJeff Roberson  *    documentation and/or other materials provided with the distribution.
14bb535300SJeff Roberson  *
15df2cf821SDavid Xu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16df2cf821SDavid Xu  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17df2cf821SDavid Xu  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18df2cf821SDavid Xu  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19df2cf821SDavid Xu  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20df2cf821SDavid Xu  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21df2cf821SDavid Xu  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22df2cf821SDavid Xu  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23df2cf821SDavid Xu  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24df2cf821SDavid Xu  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25bb535300SJeff Roberson  *
26bb535300SJeff Roberson  * $FreeBSD$
27bb535300SJeff Roberson  */
28bb535300SJeff Roberson 
2937a6356bSDavid Xu #include "namespace.h"
30bb535300SJeff Roberson #include <sys/param.h>
31bb535300SJeff Roberson #include <sys/types.h>
32bb535300SJeff Roberson #include <sys/signalvar.h>
33bb535300SJeff Roberson #include <signal.h>
34a091d823SDavid Xu #include <errno.h>
35bb535300SJeff Roberson #include <fcntl.h>
36bb535300SJeff Roberson #include <unistd.h>
37a091d823SDavid Xu #include <string.h>
38bb535300SJeff Roberson #include <pthread.h>
3937a6356bSDavid Xu #include "un-namespace.h"
4089552201SMike Makonnen 
41bb535300SJeff Roberson #include "thr_private.h"
42bb535300SJeff Roberson 
43bb535300SJeff Roberson /* #define DEBUG_SIGNAL */
44bb535300SJeff Roberson #ifdef DEBUG_SIGNAL
45bb535300SJeff Roberson #define DBG_MSG		stdout_debug
46bb535300SJeff Roberson #else
47bb535300SJeff Roberson #define DBG_MSG(x...)
48bb535300SJeff Roberson #endif
49bb535300SJeff Roberson 
5005c3a5eaSDavid Xu extern int	__pause(void);
5105c3a5eaSDavid Xu int	___pause(void);
5205c3a5eaSDavid Xu int	_raise(int);
5337a6356bSDavid Xu int	__sigtimedwait(const sigset_t *set, siginfo_t *info,
5437a6356bSDavid Xu 	const struct timespec * timeout);
55922d56f9SDavid Xu int	_sigtimedwait(const sigset_t *set, siginfo_t *info,
56922d56f9SDavid Xu 	const struct timespec * timeout);
5737a6356bSDavid Xu int	__sigwaitinfo(const sigset_t *set, siginfo_t *info);
58922d56f9SDavid Xu int	_sigwaitinfo(const sigset_t *set, siginfo_t *info);
5937a6356bSDavid Xu int	__sigwait(const sigset_t *set, int *sig);
60922d56f9SDavid Xu int	_sigwait(const sigset_t *set, int *sig);
61922d56f9SDavid Xu int	__sigsuspend(const sigset_t *sigmask);
6237a6356bSDavid Xu 
636fdfcacbSDavid Xu 
64a091d823SDavid Xu static void
6537a6356bSDavid Xu sigcancel_handler(int sig __unused,
6637a6356bSDavid Xu 	siginfo_t *info __unused, ucontext_t *ucp __unused)
67a091d823SDavid Xu {
68a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
69a091d823SDavid Xu 
701cb51125SDavid Xu 	curthread->in_sigcancel_handler++;
71bc414752SDavid Xu 	_thr_ast(curthread);
721cb51125SDavid Xu 	curthread->in_sigcancel_handler--;
73bc414752SDavid Xu }
74bc414752SDavid Xu 
75bc414752SDavid Xu void
76bc414752SDavid Xu _thr_ast(struct pthread *curthread)
77bc414752SDavid Xu {
78*635f917aSDavid Xu 
79*635f917aSDavid Xu 	if (THR_IN_CRITICAL(curthread))
80*635f917aSDavid Xu 		return;
81*635f917aSDavid Xu 
82*635f917aSDavid Xu 	if (curthread->cancel_pending && curthread->cancel_enable
83*635f917aSDavid Xu 		&& !curthread->cancelling) {
84*635f917aSDavid Xu 		if (curthread->cancel_async) {
85*635f917aSDavid Xu 			/*
86*635f917aSDavid Xu 		 	 * asynchronous cancellation mode, act upon
87*635f917aSDavid Xu 			 * immediately.
88*635f917aSDavid Xu 		 	 */
89*635f917aSDavid Xu 			_pthread_exit(PTHREAD_CANCELED);
90*635f917aSDavid Xu 		} else {
91*635f917aSDavid Xu 			/*
92*635f917aSDavid Xu 		 	 * Otherwise, we are in defer mode, and we are at
93*635f917aSDavid Xu 			 * cancel point, tell kernel to not block the current
94*635f917aSDavid Xu 			 * thread on next cancelable system call.
95*635f917aSDavid Xu 			 *
96*635f917aSDavid Xu 			 * There are two cases we should call thr_wake() to
97*635f917aSDavid Xu 			 * turn on TDP_WAKEUP in kernel:
98*635f917aSDavid Xu 			 * 1) we are going to call a cancelable system call,
99*635f917aSDavid Xu 			 *    non-zero cancel_point means we are already in
100*635f917aSDavid Xu 			 *    cancelable state, next system call is cancelable.
101*635f917aSDavid Xu 			 * 2) because _thr_ast() may be called by
102*635f917aSDavid Xu 			 *    THR_CRITICAL_LEAVE() which is used by rtld rwlock
103*635f917aSDavid Xu 			 *    and any libthr internal locks, when rtld rwlock
104*635f917aSDavid Xu 			 *    is used, it is mostly caused my an unresolved PLT.
105*635f917aSDavid Xu 			 *    those routines may clear the TDP_WAKEUP flag by
106*635f917aSDavid Xu 			 *    invoking some system calls, in those cases, we
107*635f917aSDavid Xu 			 *    also should reenable the flag.
108*635f917aSDavid Xu 		 	 */
109*635f917aSDavid Xu 			if (curthread->cancel_point) {
110*635f917aSDavid Xu 				if (curthread->cancel_defer)
111*635f917aSDavid Xu 					thr_wake(curthread->tid);
112*635f917aSDavid Xu 				else
113*635f917aSDavid Xu 					_pthread_exit(PTHREAD_CANCELED);
114*635f917aSDavid Xu 			}
115*635f917aSDavid Xu 		}
116*635f917aSDavid Xu 	}
117*635f917aSDavid Xu 
118bc414752SDavid Xu 	if (__predict_false((curthread->flags &
119bc414752SDavid Xu 	    (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
120bc414752SDavid Xu 		== THR_FLAGS_NEED_SUSPEND))
121a091d823SDavid Xu 		_thr_suspend_check(curthread);
122a091d823SDavid Xu }
123a091d823SDavid Xu 
124a091d823SDavid Xu void
125a091d823SDavid Xu _thr_suspend_check(struct pthread *curthread)
126a091d823SDavid Xu {
1278d6a11a0SDavid Xu 	uint32_t cycle;
128d448272dSDavid Xu 	int err;
129a091d823SDavid Xu 
1302ea1f90aSDavid Xu 	if (curthread->force_exit)
1312ea1f90aSDavid Xu 		return;
1322ea1f90aSDavid Xu 
133d448272dSDavid Xu 	err = errno;
134bc414752SDavid Xu 	/*
135bc414752SDavid Xu 	 * Blocks SIGCANCEL which other threads must send.
136bc414752SDavid Xu 	 */
137a091d823SDavid Xu 	_thr_signal_block(curthread);
138bc414752SDavid Xu 
139bc414752SDavid Xu 	/*
140bc414752SDavid Xu 	 * Increase critical_count, here we don't use THR_LOCK/UNLOCK
141bc414752SDavid Xu 	 * because we are leaf code, we don't want to recursively call
142bc414752SDavid Xu 	 * ourself.
143bc414752SDavid Xu 	 */
144bc414752SDavid Xu 	curthread->critical_count++;
145bddd24cdSDavid Xu 	THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
146bc414752SDavid Xu 	while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
147bc414752SDavid Xu 		THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
148bc414752SDavid Xu 		curthread->cycle++;
149a091d823SDavid Xu 		cycle = curthread->cycle;
150bc414752SDavid Xu 
151bc414752SDavid Xu 		/* Wake the thread suspending us. */
1528d6a11a0SDavid Xu 		_thr_umtx_wake(&curthread->cycle, INT_MAX, 0);
153bc414752SDavid Xu 
154bc414752SDavid Xu 		/*
155bc414752SDavid Xu 		 * if we are from pthread_exit, we don't want to
156bc414752SDavid Xu 		 * suspend, just go and die.
157bc414752SDavid Xu 		 */
158bc414752SDavid Xu 		if (curthread->state == PS_DEAD)
159bc414752SDavid Xu 			break;
160bc414752SDavid Xu 		curthread->flags |= THR_FLAGS_SUSPENDED;
161bddd24cdSDavid Xu 		THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
1628d6a11a0SDavid Xu 		_thr_umtx_wait_uint(&curthread->cycle, cycle, NULL, 0);
163bddd24cdSDavid Xu 		THR_UMUTEX_LOCK(curthread, &(curthread)->lock);
164a091d823SDavid Xu 		curthread->flags &= ~THR_FLAGS_SUSPENDED;
165a091d823SDavid Xu 	}
166bddd24cdSDavid Xu 	THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock);
167bc414752SDavid Xu 	curthread->critical_count--;
168bc414752SDavid Xu 
169bc414752SDavid Xu 	/*
170bc414752SDavid Xu 	 * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and
171bc414752SDavid Xu 	 * a new signal frame will nest us, this seems a problem because
172bc414752SDavid Xu 	 * stack will grow and overflow, but because kernel will automatically
173bc414752SDavid Xu 	 * mask the SIGCANCEL when delivering the signal, so we at most only
174bc414752SDavid Xu 	 * have one nesting signal frame, this should be fine.
175bc414752SDavid Xu 	 */
176a091d823SDavid Xu 	_thr_signal_unblock(curthread);
177d448272dSDavid Xu 	errno = err;
178a091d823SDavid Xu }
179a091d823SDavid Xu 
180a091d823SDavid Xu void
181a091d823SDavid Xu _thr_signal_init(void)
182a091d823SDavid Xu {
183a091d823SDavid Xu 	struct sigaction act;
184a091d823SDavid Xu 
185a091d823SDavid Xu 	/* Install cancel handler. */
186a091d823SDavid Xu 	SIGEMPTYSET(act.sa_mask);
187a091d823SDavid Xu 	act.sa_flags = SA_SIGINFO | SA_RESTART;
188a091d823SDavid Xu 	act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
189a091d823SDavid Xu 	__sys_sigaction(SIGCANCEL, &act, NULL);
190a091d823SDavid Xu }
191a091d823SDavid Xu 
192a091d823SDavid Xu void
193a091d823SDavid Xu _thr_signal_deinit(void)
194a091d823SDavid Xu {
195a091d823SDavid Xu }
196a091d823SDavid Xu 
19705c3a5eaSDavid Xu __weak_reference(___pause, pause);
19805c3a5eaSDavid Xu 
19905c3a5eaSDavid Xu int
20005c3a5eaSDavid Xu ___pause(void)
20105c3a5eaSDavid Xu {
20205c3a5eaSDavid Xu 	struct pthread *curthread = _get_curthread();
20305c3a5eaSDavid Xu 	int	ret;
20405c3a5eaSDavid Xu 
205f08e1bf6SDavid Xu 	_thr_cancel_enter(curthread);
20605c3a5eaSDavid Xu 	ret = __pause();
207f08e1bf6SDavid Xu 	_thr_cancel_leave(curthread);
20805c3a5eaSDavid Xu 
20905c3a5eaSDavid Xu 	return ret;
21005c3a5eaSDavid Xu }
21105c3a5eaSDavid Xu 
21205c3a5eaSDavid Xu __weak_reference(_raise, raise);
21305c3a5eaSDavid Xu 
21405c3a5eaSDavid Xu int
21505c3a5eaSDavid Xu _raise(int sig)
21605c3a5eaSDavid Xu {
21705c3a5eaSDavid Xu 	int ret;
21805c3a5eaSDavid Xu 
21905c3a5eaSDavid Xu 	if (!_thr_isthreaded())
22005c3a5eaSDavid Xu 		ret = kill(getpid(), sig);
22105c3a5eaSDavid Xu 	else
22205c3a5eaSDavid Xu 		ret = _thr_send_sig(_get_curthread(), sig);
22305c3a5eaSDavid Xu 	return (ret);
22405c3a5eaSDavid Xu }
22505c3a5eaSDavid Xu 
226a091d823SDavid Xu __weak_reference(_sigaction, sigaction);
227a091d823SDavid Xu 
228a091d823SDavid Xu int
229a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
230a091d823SDavid Xu {
231a091d823SDavid Xu 	/* Check if the signal number is out of range: */
232b144e48bSKonstantin Belousov 	if (!_SIG_VALID(sig) || sig == SIGCANCEL) {
233a091d823SDavid Xu 		/* Return an invalid argument: */
234a091d823SDavid Xu 		errno = EINVAL;
235a091d823SDavid Xu 		return (-1);
236a091d823SDavid Xu 	}
237a091d823SDavid Xu 
238a091d823SDavid Xu 	return __sys_sigaction(sig, act, oact);
239a091d823SDavid Xu }
240a091d823SDavid Xu 
241a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask);
242a091d823SDavid Xu 
243a091d823SDavid Xu int
244a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
245a091d823SDavid Xu {
246a091d823SDavid Xu 	const sigset_t *p = set;
247a091d823SDavid Xu 	sigset_t newset;
248a091d823SDavid Xu 
249a091d823SDavid Xu 	if (how != SIG_UNBLOCK) {
250a091d823SDavid Xu 		if (set != NULL) {
251a091d823SDavid Xu 			newset = *set;
252a091d823SDavid Xu 			SIGDELSET(newset, SIGCANCEL);
253a091d823SDavid Xu 			p = &newset;
254a091d823SDavid Xu 		}
255a091d823SDavid Xu 	}
256a091d823SDavid Xu 	return (__sys_sigprocmask(how, p, oset));
257a091d823SDavid Xu }
258a091d823SDavid Xu 
259bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask);
260bb535300SJeff Roberson 
261bb535300SJeff Roberson int
262bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
263bb535300SJeff Roberson {
264a091d823SDavid Xu 	if (_sigprocmask(how, set, oset))
265a091d823SDavid Xu 		return (errno);
266a091d823SDavid Xu 	return (0);
267bb535300SJeff Roberson }
268bb535300SJeff Roberson 
26905c3a5eaSDavid Xu __weak_reference(__sigsuspend, sigsuspend);
270bb535300SJeff Roberson 
271bb535300SJeff Roberson int
272a091d823SDavid Xu _sigsuspend(const sigset_t * set)
273bb535300SJeff Roberson {
27405c3a5eaSDavid Xu 	sigset_t newset;
27505c3a5eaSDavid Xu 	const sigset_t *pset;
27605c3a5eaSDavid Xu 	int ret;
27705c3a5eaSDavid Xu 
27805c3a5eaSDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
27905c3a5eaSDavid Xu 		newset = *set;
28005c3a5eaSDavid Xu 		SIGDELSET(newset, SIGCANCEL);
28105c3a5eaSDavid Xu 		pset = &newset;
28205c3a5eaSDavid Xu 	} else
28305c3a5eaSDavid Xu 		pset = set;
28405c3a5eaSDavid Xu 
28505c3a5eaSDavid Xu 	ret = __sys_sigsuspend(pset);
28605c3a5eaSDavid Xu 
28705c3a5eaSDavid Xu 	return (ret);
28805c3a5eaSDavid Xu }
28905c3a5eaSDavid Xu 
29005c3a5eaSDavid Xu int
29105c3a5eaSDavid Xu __sigsuspend(const sigset_t * set)
29205c3a5eaSDavid Xu {
293a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
294a091d823SDavid Xu 	sigset_t newset;
295a091d823SDavid Xu 	const sigset_t *pset;
296a091d823SDavid Xu 	int ret;
297bb535300SJeff Roberson 
298a091d823SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
299a091d823SDavid Xu 		newset = *set;
300a091d823SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
301a091d823SDavid Xu 		pset = &newset;
302a091d823SDavid Xu 	} else
303a091d823SDavid Xu 		pset = set;
3040ad70ba9SMike Makonnen 
305f08e1bf6SDavid Xu 	_thr_cancel_enter(curthread);
306a091d823SDavid Xu 	ret = __sys_sigsuspend(pset);
307f08e1bf6SDavid Xu 	_thr_cancel_leave(curthread);
3080ad70ba9SMike Makonnen 
309a091d823SDavid Xu 	return (ret);
310a091d823SDavid Xu }
311a091d823SDavid Xu 
312a091d823SDavid Xu __weak_reference(__sigwait, sigwait);
313a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait);
314a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo);
315a091d823SDavid Xu 
316a091d823SDavid Xu int
31705c3a5eaSDavid Xu _sigtimedwait(const sigset_t *set, siginfo_t *info,
31805c3a5eaSDavid Xu 	const struct timespec * timeout)
31905c3a5eaSDavid Xu {
32005c3a5eaSDavid Xu 	sigset_t newset;
32105c3a5eaSDavid Xu 	const sigset_t *pset;
32205c3a5eaSDavid Xu 	int ret;
32305c3a5eaSDavid Xu 
32405c3a5eaSDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
32505c3a5eaSDavid Xu 		newset = *set;
32605c3a5eaSDavid Xu 		SIGDELSET(newset, SIGCANCEL);
32705c3a5eaSDavid Xu 		pset = &newset;
32805c3a5eaSDavid Xu 	} else
32905c3a5eaSDavid Xu 		pset = set;
33005c3a5eaSDavid Xu 	ret = __sys_sigtimedwait(pset, info, timeout);
33105c3a5eaSDavid Xu 	return (ret);
33205c3a5eaSDavid Xu }
33305c3a5eaSDavid Xu 
334*635f917aSDavid Xu /*
335*635f917aSDavid Xu  * Cancellation behavior:
336*635f917aSDavid Xu  *   Thread may be canceled at start, if thread got signal,
337*635f917aSDavid Xu  *   it is not canceled.
338*635f917aSDavid Xu  */
33905c3a5eaSDavid Xu int
340a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info,
341a091d823SDavid Xu 	const struct timespec * timeout)
342a091d823SDavid Xu {
343a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
344a091d823SDavid Xu 	sigset_t newset;
345a091d823SDavid Xu 	const sigset_t *pset;
346a091d823SDavid Xu 	int ret;
347a091d823SDavid Xu 
348a091d823SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
349a091d823SDavid Xu 		newset = *set;
350a091d823SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
351a091d823SDavid Xu 		pset = &newset;
352a091d823SDavid Xu 	} else
353a091d823SDavid Xu 		pset = set;
354*635f917aSDavid Xu 	_thr_cancel_enter_defer(curthread, 1);
355a091d823SDavid Xu 	ret = __sys_sigtimedwait(pset, info, timeout);
356*635f917aSDavid Xu 	_thr_cancel_leave_defer(curthread, (ret == -1));
357a091d823SDavid Xu 	return (ret);
358a091d823SDavid Xu }
359a091d823SDavid Xu 
360a091d823SDavid Xu int
36105c3a5eaSDavid Xu _sigwaitinfo(const sigset_t *set, siginfo_t *info)
36205c3a5eaSDavid Xu {
36305c3a5eaSDavid Xu 	sigset_t newset;
36405c3a5eaSDavid Xu 	const sigset_t *pset;
36505c3a5eaSDavid Xu 	int ret;
36605c3a5eaSDavid Xu 
36705c3a5eaSDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
36805c3a5eaSDavid Xu 		newset = *set;
36905c3a5eaSDavid Xu 		SIGDELSET(newset, SIGCANCEL);
37005c3a5eaSDavid Xu 		pset = &newset;
37105c3a5eaSDavid Xu 	} else
37205c3a5eaSDavid Xu 		pset = set;
37305c3a5eaSDavid Xu 
37405c3a5eaSDavid Xu 	ret = __sys_sigwaitinfo(pset, info);
37505c3a5eaSDavid Xu 	return (ret);
37605c3a5eaSDavid Xu }
37705c3a5eaSDavid Xu 
378*635f917aSDavid Xu /*
379*635f917aSDavid Xu  * Cancellation behavior:
380*635f917aSDavid Xu  *   Thread may be canceled at start, if thread got signal,
381*635f917aSDavid Xu  *   it is not canceled.
382*635f917aSDavid Xu  */
38305c3a5eaSDavid Xu int
384a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info)
385a091d823SDavid Xu {
386a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
387a091d823SDavid Xu 	sigset_t newset;
388a091d823SDavid Xu 	const sigset_t *pset;
389a091d823SDavid Xu 	int ret;
390a091d823SDavid Xu 
391a091d823SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
392a091d823SDavid Xu 		newset = *set;
393a091d823SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
394a091d823SDavid Xu 		pset = &newset;
395a091d823SDavid Xu 	} else
396a091d823SDavid Xu 		pset = set;
397a091d823SDavid Xu 
398*635f917aSDavid Xu 	_thr_cancel_enter_defer(curthread, 1);
399a091d823SDavid Xu 	ret = __sys_sigwaitinfo(pset, info);
400*635f917aSDavid Xu 	_thr_cancel_leave_defer(curthread, ret == -1);
401a091d823SDavid Xu 	return (ret);
402a091d823SDavid Xu }
403a091d823SDavid Xu 
404a091d823SDavid Xu int
40505c3a5eaSDavid Xu _sigwait(const sigset_t *set, int *sig)
40605c3a5eaSDavid Xu {
40705c3a5eaSDavid Xu 	sigset_t newset;
40805c3a5eaSDavid Xu 	const sigset_t *pset;
40905c3a5eaSDavid Xu 	int ret;
41005c3a5eaSDavid Xu 
41105c3a5eaSDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
41205c3a5eaSDavid Xu 		newset = *set;
41305c3a5eaSDavid Xu 		SIGDELSET(newset, SIGCANCEL);
41405c3a5eaSDavid Xu 		pset = &newset;
41505c3a5eaSDavid Xu 	} else
41605c3a5eaSDavid Xu 		pset = set;
41705c3a5eaSDavid Xu 
41805c3a5eaSDavid Xu 	ret = __sys_sigwait(pset, sig);
41905c3a5eaSDavid Xu 	return (ret);
42005c3a5eaSDavid Xu }
42105c3a5eaSDavid Xu 
422*635f917aSDavid Xu /*
423*635f917aSDavid Xu  * Cancellation behavior:
424*635f917aSDavid Xu  *   Thread may be canceled at start, if thread got signal,
425*635f917aSDavid Xu  *   it is not canceled.
426*635f917aSDavid Xu  */
42705c3a5eaSDavid Xu int
428a091d823SDavid Xu __sigwait(const sigset_t *set, int *sig)
429a091d823SDavid Xu {
430a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
431a091d823SDavid Xu 	sigset_t newset;
432a091d823SDavid Xu 	const sigset_t *pset;
433a091d823SDavid Xu 	int ret;
434a091d823SDavid Xu 
435a091d823SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
436a091d823SDavid Xu 		newset = *set;
437a091d823SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
438a091d823SDavid Xu 		pset = &newset;
439a091d823SDavid Xu 	} else
440a091d823SDavid Xu 		pset = set;
441a091d823SDavid Xu 
442*635f917aSDavid Xu 	_thr_cancel_enter_defer(curthread, 1);
443a091d823SDavid Xu 	ret = __sys_sigwait(pset, sig);
444*635f917aSDavid Xu 	_thr_cancel_leave_defer(curthread, (ret != 0));
445a091d823SDavid Xu 	return (ret);
446bb535300SJeff Roberson }
447