thr_sigwait.c revision 117216
1103419Smini//depot/projects/kse/lib/libpthread/thread/thr_sigwait.c#1 - branch change 15154 (text+ko)
222315Sjulian/*
322315Sjulian * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
422315Sjulian * All rights reserved.
522315Sjulian *
622315Sjulian * Redistribution and use in source and binary forms, with or without
722315Sjulian * modification, are permitted provided that the following conditions
822315Sjulian * are met:
922315Sjulian * 1. Redistributions of source code must retain the above copyright
1022315Sjulian *    notice, this list of conditions and the following disclaimer.
1122315Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1222315Sjulian *    notice, this list of conditions and the following disclaimer in the
1322315Sjulian *    documentation and/or other materials provided with the distribution.
1422315Sjulian * 3. All advertising materials mentioning features or use of this software
1522315Sjulian *    must display the following acknowledgement:
1622315Sjulian *	This product includes software developed by John Birrell.
1722315Sjulian * 4. Neither the name of the author nor the names of any co-contributors
1822315Sjulian *    may be used to endorse or promote products derived from this software
1922315Sjulian *    without specific prior written permission.
2022315Sjulian *
2122315Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
2222315Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2322315Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2449439Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2522315Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2622315Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2722315Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2822315Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2922315Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3022315Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3122315Sjulian * SUCH DAMAGE.
3222315Sjulian *
3350476Speter * $FreeBSD: head/lib/libkse/thread/thr_sigwait.c 117216 2003-07-04 07:49:06Z davidxu $
3422315Sjulian */
3522315Sjulian#include <signal.h>
3651816Smarcel#include <sys/param.h>
3751816Smarcel#include <sys/signalvar.h>
3822315Sjulian#include <errno.h>
3922315Sjulian#include <pthread.h>
40103388Smini#include "thr_private.h"
4122315Sjulian
42116977Sdavidxu__weak_reference(__sigwait, sigwait);
43116977Sdavidxu__weak_reference(__sigtimedwait, sigtimedwait);
44116977Sdavidxu__weak_reference(__sigwaitinfo, sigwaitinfo);
4571581Sdeischen
46116977Sdavidxustatic int
47116977Sdavidxulib_sigtimedwait(const sigset_t *set, siginfo_t *info,
48116977Sdavidxu	const struct timespec * timeout)
4922315Sjulian{
50113658Sdeischen	struct pthread	*curthread = _get_curthread();
51113658Sdeischen	int		ret = 0;
52113658Sdeischen	int		i;
53113658Sdeischen	sigset_t	tempset, waitset;
54113658Sdeischen	struct sigaction act;
55114254Sdeischen	kse_critical_t  crit;
56116977Sdavidxu	siginfo_t	siginfo;
57114254Sdeischen
58116977Sdavidxu	if (!_kse_isthreaded()) {
59116977Sdavidxu		if (info == NULL)
60116977Sdavidxu			info = &siginfo;
61116977Sdavidxu		return __sys_sigtimedwait((sigset_t *)set, info,
62116977Sdavidxu			(struct timespec *)timeout);
63116977Sdavidxu	}
6422315Sjulian
6538539Sjb	/*
66113658Sdeischen	 * Specify the thread kernel signal handler.
6738539Sjb	 */
68113658Sdeischen	act.sa_handler = (void (*) ()) _thr_sig_handler;
69113658Sdeischen	act.sa_flags = SA_RESTART | SA_SIGINFO;
70113658Sdeischen	/* Ensure the signal handler cannot be interrupted by other signals: */
71116977Sdavidxu	SIGFILLSET(act.sa_mask);
72113658Sdeischen
73113658Sdeischen	/*
74113658Sdeischen	 * Initialize the set of signals that will be waited on:
75113658Sdeischen	 */
76113658Sdeischen	waitset = *set;
77113658Sdeischen
78113658Sdeischen	/* These signals can't be waited on. */
79116977Sdavidxu	SIGDELSET(waitset, SIGKILL);
80116977Sdavidxu	SIGDELSET(waitset, SIGSTOP);
81113658Sdeischen
82114254Sdeischen	crit = _kse_critical_enter();
83114254Sdeischen	KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
84113658Sdeischen
85113658Sdeischen	/*
86116977Sdavidxu	 * Enter a loop to find the signals that are SIG_DFL. For
87113658Sdeischen	 * these signals we must install a dummy signal handler in
88113658Sdeischen	 * order for the kernel to pass them in to us.  POSIX says
89113658Sdeischen	 * that the _application_ must explicitly install a dummy
90113658Sdeischen	 * handler for signals that are SIG_IGN in order to sigwait
91113658Sdeischen	 * on them.  Note that SIG_IGN signals are left in the
92113658Sdeischen	 * mask because a subsequent sigaction could enable an
93113658Sdeischen	 * ignored signal.
94113658Sdeischen	 */
95116977Sdavidxu	SIGEMPTYSET(tempset);
96116977Sdavidxu	for (i = 1; i <= _SIG_MAXSIG; i++) {
97116977Sdavidxu		if (SIGISMEMBER(waitset, i) &&
98113658Sdeischen		    (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
99116977Sdavidxu			_thread_dfl_count[i - 1]++;
100116977Sdavidxu			SIGADDSET(tempset, i);
101116977Sdavidxu			if (_thread_dfl_count[i - 1] == 1) {
102113658Sdeischen				if (__sys_sigaction(i, &act, NULL) != 0)
103116977Sdavidxu					/* ret = -1 */;
104113658Sdeischen			}
105113658Sdeischen		}
106113658Sdeischen	}
107116977Sdavidxu
108113658Sdeischen	if (ret == 0) {
109116977Sdavidxu		/* Done accessing _thread_dfl_count for now. */
110116977Sdavidxu		KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
111116977Sdavidxu		KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
112116977Sdavidxu		for (i = 1; i <= _SIG_MAXSIG; ++i) {
113116977Sdavidxu			if (SIGISMEMBER(waitset, i) &&
114116977Sdavidxu			    SIGISMEMBER(curthread->sigpend, i)) {
115116977Sdavidxu				SIGDELSET(curthread->sigpend, i);
116117216Sdavidxu				siginfo = curthread->siginfo[i - 1];
117116977Sdavidxu				KSE_SCHED_UNLOCK(curthread->kse,
118116977Sdavidxu					curthread->kseg);
119116977Sdavidxu				_kse_critical_leave(crit);
120117216Sdavidxu				ret = i;
121117216Sdavidxu				goto OUT;
122116977Sdavidxu			}
123116977Sdavidxu		}
124116977Sdavidxu		curthread->timeout = 0;
125116977Sdavidxu		_thr_set_timeout(timeout);
126113658Sdeischen		/* Wait for a signal: */
127116977Sdavidxu		curthread->oldsigmask = curthread->sigmask;
128116977Sdavidxu		siginfo.si_signo = 0;
129116977Sdavidxu		curthread->data.sigwaitinfo = &siginfo;
130116977Sdavidxu		SIGFILLSET(curthread->sigmask);
131116977Sdavidxu		SIGSETNAND(curthread->sigmask, waitset);
132113658Sdeischen		THR_SET_STATE(curthread, PS_SIGWAIT);
133115080Sdeischen		_thr_sched_switch_unlocked(curthread);
134116977Sdavidxu		/*
135116977Sdavidxu		 * Return the signal number to the caller:
136116977Sdavidxu		 * XXX Here is race, how about a signal come in before
137116977Sdavidxu		 * we reach here? so we might got an incorrect timeout
138116977Sdavidxu		 * status.
139116977Sdavidxu		 */
140116977Sdavidxu		if (siginfo.si_signo > 0) {
141116977Sdavidxu			ret = siginfo.si_signo;
142116977Sdavidxu		} else {
143116977Sdavidxu			if (curthread->timeout)
144116977Sdavidxu				errno = EAGAIN;
145116977Sdavidxu			ret = -1;
146116977Sdavidxu		}
147113658Sdeischen
148113658Sdeischen		/*
149113658Sdeischen		 * Probably unnecessary, but since it's in a union struct
150113658Sdeischen		 * we don't know how it could be used in the future.
151113658Sdeischen		 */
152116977Sdavidxu		crit = _kse_critical_enter();
153116977Sdavidxu		curthread->data.sigwaitinfo = NULL;
154116977Sdavidxu		/*
155116977Sdavidxu		 * Relock the array of SIG_DFL wait counts.
156116977Sdavidxu		 */
157116977Sdavidxu		KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
158113658Sdeischen	}
159113658Sdeischen
160117216SdavidxuOUT:
161113658Sdeischen	/* Restore the sigactions: */
162113658Sdeischen	act.sa_handler = SIG_DFL;
163116977Sdavidxu	for (i = 1; i <= _SIG_MAXSIG; i++) {
164116977Sdavidxu		if (SIGISMEMBER(tempset, i)) {
165116977Sdavidxu			_thread_dfl_count[i - 1]--;
166113658Sdeischen			if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
167116977Sdavidxu			    (_thread_dfl_count[i - 1] == 0)) {
168113658Sdeischen				if (__sys_sigaction(i, &act, NULL) != 0)
169116977Sdavidxu					/* ret = -1 */ ;
170113658Sdeischen			}
171113658Sdeischen		}
172113658Sdeischen	}
173113658Sdeischen	/* Done accessing _thread_dfl_count. */
174114254Sdeischen	KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
175114254Sdeischen	_kse_critical_leave(crit);
176116977Sdavidxu
177117216Sdavidxu	if (ret > 0 && info != NULL)
178117216Sdavidxu		*info = siginfo;
179117216Sdavidxu
180116977Sdavidxu	return (ret);
181116977Sdavidxu}
182116977Sdavidxu
183116977Sdavidxuint
184116977Sdavidxu__sigtimedwait(const sigset_t *set, siginfo_t *info,
185116977Sdavidxu	const struct timespec * timeout)
186116977Sdavidxu{
187116977Sdavidxu	struct pthread	*curthread = _get_curthread();
188116977Sdavidxu	int ret;
189116977Sdavidxu
190116977Sdavidxu	_thr_enter_cancellation_point(curthread);
191116977Sdavidxu	ret = lib_sigtimedwait(set, info, timeout);
192114254Sdeischen	_thr_leave_cancellation_point(curthread);
193116977Sdavidxu	return (ret);
194116977Sdavidxu}
195113658Sdeischen
196116977Sdavidxuint _sigtimedwait(const sigset_t *set, siginfo_t *info,
197116977Sdavidxu	const struct timespec * timeout)
198116977Sdavidxu{
199116977Sdavidxu	return lib_sigtimedwait(set, info, timeout);
200116977Sdavidxu}
201116977Sdavidxu
202116977Sdavidxuint
203116977Sdavidxu__sigwaitinfo(const sigset_t *set, siginfo_t *info)
204116977Sdavidxu{
205116977Sdavidxu	struct pthread	*curthread = _get_curthread();
206116977Sdavidxu	int ret;
207116977Sdavidxu
208116977Sdavidxu	_thr_enter_cancellation_point(curthread);
209116977Sdavidxu	ret = lib_sigtimedwait(set, info, NULL);
210116977Sdavidxu	_thr_leave_cancellation_point(curthread);
211113658Sdeischen	return (ret);
21222315Sjulian}
213116977Sdavidxu
214116977Sdavidxuint
215116977Sdavidxu_sigwaitinfo(const sigset_t *set, siginfo_t *info)
216116977Sdavidxu{
217116977Sdavidxu	return lib_sigtimedwait(set, info, NULL);
218116977Sdavidxu}
219116977Sdavidxu
220116977Sdavidxuint
221116977Sdavidxu__sigwait(const sigset_t *set, int *sig)
222116977Sdavidxu{
223116977Sdavidxu	struct pthread	*curthread = _get_curthread();
224116977Sdavidxu	int ret;
225116977Sdavidxu
226116977Sdavidxu	_thr_enter_cancellation_point(curthread);
227116977Sdavidxu	ret = lib_sigtimedwait(set, NULL, NULL);
228116977Sdavidxu	if (ret > 0) {
229116977Sdavidxu		*sig = ret;
230116977Sdavidxu		ret = 0;
231116977Sdavidxu	}
232116977Sdavidxu	else
233116977Sdavidxu		ret = -1;
234116977Sdavidxu	_thr_leave_cancellation_point(curthread);
235116977Sdavidxu	return (ret);
236116977Sdavidxu}
237116977Sdavidxu
238116977Sdavidxuint
239116977Sdavidxu_sigwait(const sigset_t *set, int *sig)
240116977Sdavidxu{
241116977Sdavidxu	int ret;
242116977Sdavidxu
243116977Sdavidxu	ret = lib_sigtimedwait(set, NULL, NULL);
244116977Sdavidxu	if (ret > 0) {
245116977Sdavidxu		*sig = ret;
246116977Sdavidxu		ret = 0;
247116977Sdavidxu	} else {
248116977Sdavidxu		ret = -1;
249116977Sdavidxu	}
250116977Sdavidxu	return (ret);
251116977Sdavidxu}
252116977Sdavidxu
253