thr_sigwait.c revision 116977
1//depot/projects/kse/lib/libpthread/thread/thr_sigwait.c#1 - branch change 15154 (text+ko)
2/*
3 * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following 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 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by John Birrell.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $FreeBSD: head/lib/libkse/thread/thr_sigwait.c 116977 2003-06-28 09:55:02Z davidxu $
34 */
35#include <signal.h>
36#include <sys/param.h>
37#include <sys/signalvar.h>
38#include <errno.h>
39#include <pthread.h>
40#include "thr_private.h"
41
42__weak_reference(__sigwait, sigwait);
43__weak_reference(__sigtimedwait, sigtimedwait);
44__weak_reference(__sigwaitinfo, sigwaitinfo);
45
46static int
47lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
48	const struct timespec * timeout)
49{
50	struct pthread	*curthread = _get_curthread();
51	int		ret = 0;
52	int		i;
53	sigset_t	tempset, waitset;
54	struct sigaction act;
55	kse_critical_t  crit;
56	siginfo_t	siginfo;
57
58	if (!_kse_isthreaded()) {
59		if (info == NULL)
60			info = &siginfo;
61		return __sys_sigtimedwait((sigset_t *)set, info,
62			(struct timespec *)timeout);
63	}
64
65	/*
66	 * Specify the thread kernel signal handler.
67	 */
68	act.sa_handler = (void (*) ()) _thr_sig_handler;
69	act.sa_flags = SA_RESTART | SA_SIGINFO;
70	/* Ensure the signal handler cannot be interrupted by other signals: */
71	SIGFILLSET(act.sa_mask);
72
73	/*
74	 * Initialize the set of signals that will be waited on:
75	 */
76	waitset = *set;
77
78	/* These signals can't be waited on. */
79	SIGDELSET(waitset, SIGKILL);
80	SIGDELSET(waitset, SIGSTOP);
81
82	crit = _kse_critical_enter();
83	KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
84
85	/*
86	 * Enter a loop to find the signals that are SIG_DFL. For
87	 * these signals we must install a dummy signal handler in
88	 * order for the kernel to pass them in to us.  POSIX says
89	 * that the _application_ must explicitly install a dummy
90	 * handler for signals that are SIG_IGN in order to sigwait
91	 * on them.  Note that SIG_IGN signals are left in the
92	 * mask because a subsequent sigaction could enable an
93	 * ignored signal.
94	 */
95	SIGEMPTYSET(tempset);
96	for (i = 1; i <= _SIG_MAXSIG; i++) {
97		if (SIGISMEMBER(waitset, i) &&
98		    (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
99			_thread_dfl_count[i - 1]++;
100			SIGADDSET(tempset, i);
101			if (_thread_dfl_count[i - 1] == 1) {
102				if (__sys_sigaction(i, &act, NULL) != 0)
103					/* ret = -1 */;
104			}
105		}
106	}
107
108	if (ret == 0) {
109		/* Done accessing _thread_dfl_count for now. */
110		KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
111		KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
112		for (i = 1; i <= _SIG_MAXSIG; ++i) {
113			if (SIGISMEMBER(waitset, i) &&
114			    SIGISMEMBER(curthread->sigpend, i)) {
115				SIGDELSET(curthread->sigpend, i);
116				*info = curthread->siginfo[i];
117				KSE_SCHED_UNLOCK(curthread->kse,
118					curthread->kseg);
119				_kse_critical_leave(crit);
120				return (i);
121			}
122		}
123		curthread->timeout = 0;
124		_thr_set_timeout(timeout);
125		/* Wait for a signal: */
126		curthread->oldsigmask = curthread->sigmask;
127		siginfo.si_signo = 0;
128		curthread->data.sigwaitinfo = &siginfo;
129		SIGFILLSET(curthread->sigmask);
130		SIGSETNAND(curthread->sigmask, waitset);
131		THR_SET_STATE(curthread, PS_SIGWAIT);
132		_thr_sched_switch_unlocked(curthread);
133		/*
134		 * Return the signal number to the caller:
135		 * XXX Here is race, how about a signal come in before
136		 * we reach here? so we might got an incorrect timeout
137		 * status.
138		 */
139		if (siginfo.si_signo > 0) {
140			if (info)
141				*info = siginfo;
142			ret = siginfo.si_signo;
143		} else {
144			if (curthread->timeout)
145				errno = EAGAIN;
146			ret = -1;
147		}
148
149		/*
150		 * Probably unnecessary, but since it's in a union struct
151		 * we don't know how it could be used in the future.
152		 */
153		crit = _kse_critical_enter();
154		curthread->data.sigwaitinfo = NULL;
155		/*
156		 * Relock the array of SIG_DFL wait counts.
157		 */
158		KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
159	}
160
161	/* Restore the sigactions: */
162	act.sa_handler = SIG_DFL;
163	for (i = 1; i <= _SIG_MAXSIG; i++) {
164		if (SIGISMEMBER(tempset, i)) {
165			_thread_dfl_count[i - 1]--;
166			if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
167			    (_thread_dfl_count[i - 1] == 0)) {
168				if (__sys_sigaction(i, &act, NULL) != 0)
169					/* ret = -1 */ ;
170			}
171		}
172	}
173	/* Done accessing _thread_dfl_count. */
174	KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
175	_kse_critical_leave(crit);
176
177	return (ret);
178}
179
180int
181__sigtimedwait(const sigset_t *set, siginfo_t *info,
182	const struct timespec * timeout)
183{
184	struct pthread	*curthread = _get_curthread();
185	int ret;
186
187	_thr_enter_cancellation_point(curthread);
188	ret = lib_sigtimedwait(set, info, timeout);
189	_thr_leave_cancellation_point(curthread);
190	return (ret);
191}
192
193int _sigtimedwait(const sigset_t *set, siginfo_t *info,
194	const struct timespec * timeout)
195{
196	return lib_sigtimedwait(set, info, timeout);
197}
198
199int
200__sigwaitinfo(const sigset_t *set, siginfo_t *info)
201{
202	struct pthread	*curthread = _get_curthread();
203	int ret;
204
205	_thr_enter_cancellation_point(curthread);
206	ret = lib_sigtimedwait(set, info, NULL);
207	_thr_leave_cancellation_point(curthread);
208	return (ret);
209}
210
211int
212_sigwaitinfo(const sigset_t *set, siginfo_t *info)
213{
214	return lib_sigtimedwait(set, info, NULL);
215}
216
217int
218__sigwait(const sigset_t *set, int *sig)
219{
220	struct pthread	*curthread = _get_curthread();
221	int ret;
222
223	_thr_enter_cancellation_point(curthread);
224	ret = lib_sigtimedwait(set, NULL, NULL);
225	if (ret > 0) {
226		*sig = ret;
227		ret = 0;
228	}
229	else
230		ret = -1;
231	_thr_leave_cancellation_point(curthread);
232	return (ret);
233}
234
235int
236_sigwait(const sigset_t *set, int *sig)
237{
238	int ret;
239
240	ret = lib_sigtimedwait(set, NULL, NULL);
241	if (ret > 0) {
242		*sig = ret;
243		ret = 0;
244	} else {
245		ret = -1;
246	}
247	return (ret);
248}
249
250