thr_sigwait.c revision 113658
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 113658 2003-04-18 05:04:16Z deischen $
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
44int
45_sigwait(const sigset_t *set, int *sig)
46{
47	struct pthread	*curthread = _get_curthread();
48	int		ret = 0;
49	int		i;
50	sigset_t	tempset, waitset;
51	struct sigaction act;
52
53	_thr_enter_cancellation_point(curthread);
54
55	/*
56	 * Specify the thread kernel signal handler.
57	 */
58	act.sa_handler = (void (*) ()) _thr_sig_handler;
59	act.sa_flags = SA_RESTART | SA_SIGINFO;
60	/* Ensure the signal handler cannot be interrupted by other signals: */
61	sigfillset(&act.sa_mask);
62
63	/*
64	 * Initialize the set of signals that will be waited on:
65	 */
66	waitset = *set;
67
68	/* These signals can't be waited on. */
69	sigdelset(&waitset, SIGKILL);
70	sigdelset(&waitset, SIGSTOP);
71
72	/*
73	 * Check to see if a pending signal is in the wait mask.
74	 * This has to be atomic. */
75	tempset = curthread->sigpend;
76	SIGSETOR(tempset, _thr_proc_sigpending);
77	SIGSETAND(tempset, waitset);
78	if (SIGNOTEMPTY(tempset)) {
79		/* Enter a loop to find a pending signal: */
80		for (i = 1; i < NSIG; i++) {
81			if (sigismember (&tempset, i))
82				break;
83		}
84
85		/* Clear the pending signal: */
86		if (sigismember(&curthread->sigpend,i))
87			sigdelset(&curthread->sigpend,i);
88		else
89			sigdelset(&_thr_proc_sigpending,i);
90
91		/* Return the signal number to the caller: */
92		*sig = i;
93
94		_thr_leave_cancellation_point(curthread);
95		return (0);
96	}
97
98	/*
99	 * Lock the array of SIG_DFL wait counts.
100	 */
101	THR_LOCK_ACQUIRE(curthread, &_thread_signal_lock);
102
103	/*
104	 * Enter a loop to find the signals that are SIG_DFL.  For
105	 * these signals we must install a dummy signal handler in
106	 * order for the kernel to pass them in to us.  POSIX says
107	 * that the _application_ must explicitly install a dummy
108	 * handler for signals that are SIG_IGN in order to sigwait
109	 * on them.  Note that SIG_IGN signals are left in the
110	 * mask because a subsequent sigaction could enable an
111	 * ignored signal.
112	 */
113	sigemptyset(&tempset);
114	for (i = 1; i < NSIG; i++) {
115		if (sigismember(&waitset, i) &&
116		    (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
117			_thread_dfl_count[i]++;
118			sigaddset(&tempset, i);
119			if (_thread_dfl_count[i] == 1) {
120				if (__sys_sigaction(i, &act, NULL) != 0)
121					ret = -1;
122			}
123		}
124	}
125	/* Done accessing _thread_dfl_count for now. */
126	THR_LOCK_RELEASE(curthread, &_thread_signal_lock);
127
128	if (ret == 0) {
129		/*
130		 * Save the wait signal mask.  The wait signal
131		 * mask is independent of the threads signal mask
132		 * and requires separate storage.
133		 */
134		curthread->data.sigwait = &waitset;
135
136		/* Wait for a signal: */
137		THR_SCHED_LOCK(curthread, curthread);
138		THR_SET_STATE(curthread, PS_SIGWAIT);
139		THR_SCHED_UNLOCK(curthread, curthread);
140		_thr_sched_switch(curthread);
141
142		/* Return the signal number to the caller: */
143		*sig = curthread->signo;
144
145		/*
146		 * Probably unnecessary, but since it's in a union struct
147		 * we don't know how it could be used in the future.
148		 */
149		curthread->data.sigwait = NULL;
150	}
151
152	/*
153	 * Relock the array of SIG_DFL wait counts.
154	 */
155	THR_LOCK_ACQUIRE(curthread, &_thread_signal_lock);
156
157	/* Restore the sigactions: */
158	act.sa_handler = SIG_DFL;
159	for (i = 1; i < NSIG; i++) {
160		if (sigismember(&tempset, i)) {
161			_thread_dfl_count[i]--;
162			if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
163			    (_thread_dfl_count[i] == 0)) {
164				if (__sys_sigaction(i, &act, NULL) != 0)
165					ret = -1;
166			}
167		}
168	}
169	/* Done accessing _thread_dfl_count. */
170	THR_LOCK_RELEASE(curthread, &_thread_signal_lock);
171
172	_thr_leave_cancellation_point(curthread);
173
174	/* Return the completion status: */
175	return (ret);
176}
177