xref: /freebsd/lib/libthr/thread/thr_sig.c (revision df2cf821785223c7c8ed39582a1dda995a557a40)
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 
29bb535300SJeff Roberson #include <sys/param.h>
30bb535300SJeff Roberson #include <sys/types.h>
31bb535300SJeff Roberson #include <sys/signalvar.h>
32bb535300SJeff Roberson #include <signal.h>
33a091d823SDavid Xu #include <errno.h>
34bb535300SJeff Roberson #include <fcntl.h>
35bb535300SJeff Roberson #include <unistd.h>
36a091d823SDavid Xu #include <string.h>
37bb535300SJeff Roberson #include <pthread.h>
3889552201SMike Makonnen 
39bb535300SJeff Roberson #include "thr_private.h"
40bb535300SJeff Roberson 
41bb535300SJeff Roberson /* #define DEBUG_SIGNAL */
42bb535300SJeff Roberson #ifdef DEBUG_SIGNAL
43bb535300SJeff Roberson #define DBG_MSG		stdout_debug
44bb535300SJeff Roberson #else
45bb535300SJeff Roberson #define DBG_MSG(x...)
46bb535300SJeff Roberson #endif
47bb535300SJeff Roberson 
48a091d823SDavid Xu static void
49a091d823SDavid Xu sigcancel_handler(int sig, siginfo_t *info, ucontext_t *ucp)
50a091d823SDavid Xu {
51a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
52a091d823SDavid Xu 
53a091d823SDavid Xu 	if (curthread->cancelflags & THR_CANCEL_AT_POINT)
54a091d823SDavid Xu 		pthread_testcancel();
55a091d823SDavid Xu 	if (curthread->flags & THR_FLAGS_NEED_SUSPEND) {
56a091d823SDavid Xu 		__sys_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL);
57a091d823SDavid Xu 		_thr_suspend_check(curthread);
58a091d823SDavid Xu 	}
59a091d823SDavid Xu }
60a091d823SDavid Xu 
61a091d823SDavid Xu void
62a091d823SDavid Xu _thr_suspend_check(struct pthread *curthread)
63a091d823SDavid Xu {
64a091d823SDavid Xu 	long cycle;
65a091d823SDavid Xu 
66a091d823SDavid Xu 	/* Async suspend. */
67a091d823SDavid Xu 	_thr_signal_block(curthread);
68a091d823SDavid Xu 	THR_LOCK(curthread);
69a091d823SDavid Xu 	if ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
70a091d823SDavid Xu 		== THR_FLAGS_NEED_SUSPEND) {
71a091d823SDavid Xu 		curthread->flags |= THR_FLAGS_SUSPENDED;
72a091d823SDavid Xu 		while (curthread->flags & THR_FLAGS_NEED_SUSPEND) {
73a091d823SDavid Xu 			cycle = curthread->cycle;
74a091d823SDavid Xu 			THR_UNLOCK(curthread);
75a091d823SDavid Xu 			_thr_signal_unblock(curthread);
76a091d823SDavid Xu 			_thr_umtx_wait(&curthread->cycle, cycle, NULL);
77a091d823SDavid Xu 			_thr_signal_block(curthread);
78a091d823SDavid Xu 			THR_LOCK(curthread);
79a091d823SDavid Xu 		}
80a091d823SDavid Xu 		curthread->flags &= ~THR_FLAGS_SUSPENDED;
81a091d823SDavid Xu 	}
82a091d823SDavid Xu 	THR_UNLOCK(curthread);
83a091d823SDavid Xu 	_thr_signal_unblock(curthread);
84a091d823SDavid Xu }
85a091d823SDavid Xu 
86a091d823SDavid Xu void
87a091d823SDavid Xu _thr_signal_init(void)
88a091d823SDavid Xu {
89a091d823SDavid Xu 	struct sigaction act;
90a091d823SDavid Xu 
91a091d823SDavid Xu 	/* Install cancel handler. */
92a091d823SDavid Xu 	SIGEMPTYSET(act.sa_mask);
93a091d823SDavid Xu 	act.sa_flags = SA_SIGINFO | SA_RESTART;
94a091d823SDavid Xu 	act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
95a091d823SDavid Xu 	__sys_sigaction(SIGCANCEL, &act, NULL);
96a091d823SDavid Xu }
97a091d823SDavid Xu 
98a091d823SDavid Xu void
99a091d823SDavid Xu _thr_signal_deinit(void)
100a091d823SDavid Xu {
101a091d823SDavid Xu }
102a091d823SDavid Xu 
103a091d823SDavid Xu __weak_reference(_sigaction, sigaction);
104a091d823SDavid Xu 
105a091d823SDavid Xu int
106a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
107a091d823SDavid Xu {
108a091d823SDavid Xu 	/* Check if the signal number is out of range: */
109a091d823SDavid Xu 	if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) {
110a091d823SDavid Xu 		/* Return an invalid argument: */
111a091d823SDavid Xu 		errno = EINVAL;
112a091d823SDavid Xu 		return (-1);
113a091d823SDavid Xu 	}
114a091d823SDavid Xu 
115a091d823SDavid Xu 	return __sys_sigaction(sig, act, oact);
116a091d823SDavid Xu }
117a091d823SDavid Xu 
118a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask);
119a091d823SDavid Xu 
120a091d823SDavid Xu int
121a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
122a091d823SDavid Xu {
123a091d823SDavid Xu 	const sigset_t *p = set;
124a091d823SDavid Xu 	sigset_t newset;
125a091d823SDavid Xu 
126a091d823SDavid Xu 	if (how != SIG_UNBLOCK) {
127a091d823SDavid Xu 		if (set != NULL) {
128a091d823SDavid Xu 			newset = *set;
129a091d823SDavid Xu 			SIGDELSET(newset, SIGCANCEL);
130a091d823SDavid Xu 			p = &newset;
131a091d823SDavid Xu 		}
132a091d823SDavid Xu 	}
133a091d823SDavid Xu 	return (__sys_sigprocmask(how, p, oset));
134a091d823SDavid Xu }
135a091d823SDavid Xu 
136bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask);
137bb535300SJeff Roberson 
138bb535300SJeff Roberson int
139bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
140bb535300SJeff Roberson {
141a091d823SDavid Xu 	if (_sigprocmask(how, set, oset))
142a091d823SDavid Xu 		return (errno);
143a091d823SDavid Xu 	return (0);
144bb535300SJeff Roberson }
145bb535300SJeff Roberson 
146a091d823SDavid Xu __weak_reference(_sigsuspend, sigsuspend);
147bb535300SJeff Roberson 
148bb535300SJeff Roberson int
149a091d823SDavid Xu _sigsuspend(const sigset_t * set)
150bb535300SJeff Roberson {
151a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
152a091d823SDavid Xu 	sigset_t newset;
153a091d823SDavid Xu 	const sigset_t *pset;
154a091d823SDavid Xu 	int oldcancel;
155a091d823SDavid Xu 	int ret;
156bb535300SJeff Roberson 
157a091d823SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
158a091d823SDavid Xu 		newset = *set;
159a091d823SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
160a091d823SDavid Xu 		pset = &newset;
161a091d823SDavid Xu 	} else
162a091d823SDavid Xu 		pset = set;
1630ad70ba9SMike Makonnen 
164a091d823SDavid Xu 	oldcancel = _thr_cancel_enter(curthread);
165a091d823SDavid Xu 	ret = __sys_sigsuspend(pset);
166a091d823SDavid Xu 	_thr_cancel_leave(curthread, oldcancel);
1670ad70ba9SMike Makonnen 
168a091d823SDavid Xu 	return (ret);
169a091d823SDavid Xu }
170a091d823SDavid Xu 
171a091d823SDavid Xu __weak_reference(__sigwait, sigwait);
172a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait);
173a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo);
174a091d823SDavid Xu 
175a091d823SDavid Xu int
176a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info,
177a091d823SDavid Xu 	const struct timespec * timeout)
178a091d823SDavid Xu {
179a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
180a091d823SDavid Xu 	sigset_t newset;
181a091d823SDavid Xu 	const sigset_t *pset;
182a091d823SDavid Xu 	int oldcancel;
183a091d823SDavid Xu 	int ret;
184a091d823SDavid Xu 
185a091d823SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
186a091d823SDavid Xu 		newset = *set;
187a091d823SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
188a091d823SDavid Xu 		pset = &newset;
189a091d823SDavid Xu 	} else
190a091d823SDavid Xu 		pset = set;
191a091d823SDavid Xu 	oldcancel = _thr_cancel_enter(curthread);
192a091d823SDavid Xu 	ret = __sys_sigtimedwait(pset, info, timeout);
193a091d823SDavid Xu 	_thr_cancel_leave(curthread, oldcancel);
194a091d823SDavid Xu 	return (ret);
195a091d823SDavid Xu }
196a091d823SDavid Xu 
197a091d823SDavid Xu int
198a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info)
199a091d823SDavid Xu {
200a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
201a091d823SDavid Xu 	sigset_t newset;
202a091d823SDavid Xu 	const sigset_t *pset;
203a091d823SDavid Xu 	int oldcancel;
204a091d823SDavid Xu 	int ret;
205a091d823SDavid Xu 
206a091d823SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
207a091d823SDavid Xu 		newset = *set;
208a091d823SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
209a091d823SDavid Xu 		pset = &newset;
210a091d823SDavid Xu 	} else
211a091d823SDavid Xu 		pset = set;
212a091d823SDavid Xu 
213a091d823SDavid Xu 	oldcancel = _thr_cancel_enter(curthread);
214a091d823SDavid Xu 	ret = __sys_sigwaitinfo(pset, info);
215a091d823SDavid Xu 	_thr_cancel_leave(curthread, oldcancel);
216a091d823SDavid Xu 	return (ret);
217a091d823SDavid Xu }
218a091d823SDavid Xu 
219a091d823SDavid Xu int
220a091d823SDavid Xu __sigwait(const sigset_t *set, int *sig)
221a091d823SDavid Xu {
222a091d823SDavid Xu 	struct pthread	*curthread = _get_curthread();
223a091d823SDavid Xu 	sigset_t newset;
224a091d823SDavid Xu 	const sigset_t *pset;
225a091d823SDavid Xu 	int oldcancel;
226a091d823SDavid Xu 	int ret;
227a091d823SDavid Xu 
228a091d823SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
229a091d823SDavid Xu 		newset = *set;
230a091d823SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
231a091d823SDavid Xu 		pset = &newset;
232a091d823SDavid Xu 	} else
233a091d823SDavid Xu 		pset = set;
234a091d823SDavid Xu 
235a091d823SDavid Xu 	oldcancel = _thr_cancel_enter(curthread);
236a091d823SDavid Xu 	ret = __sys_sigwait(pset, sig);
237a091d823SDavid Xu 	_thr_cancel_leave(curthread, oldcancel);
238a091d823SDavid Xu 	return (ret);
239bb535300SJeff Roberson }
240