1251881Speter/*
2251881Speter * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
3251881Speter * All rights reserved.
4251881Speter *
5251881Speter * Redistribution and use in source and binary forms, with or without
6251881Speter * modification, are permitted provided that the following conditions
7251881Speter * are met:
8251881Speter * 1. Redistributions of source code must retain the above copyright
9251881Speter *    notice, this list of conditions and the following disclaimer.
10251881Speter * 2. Redistributions in binary form must reproduce the above copyright
11251881Speter *    notice, this list of conditions and the following disclaimer in the
12251881Speter *    documentation and/or other materials provided with the distribution.
13251881Speter * 3. All advertising materials mentioning features or use of this software
14251881Speter *    must display the following acknowledgement:
15251881Speter *	This product includes software developed by Daniel M. Eischen.
16251881Speter * 4. Neither the name of the author nor the names of any co-contributors
17251881Speter *    may be used to endorse or promote products derived from this software
18251881Speter *    without specific prior written permission.
19251881Speter *
20251881Speter * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
21251881Speter * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23251881Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30251881Speter * SUCH DAMAGE.
31251881Speter *
32251881Speter * $FreeBSD$
33251881Speter */
34251881Speter#include <stdlib.h>
35251881Speter#include <unistd.h>
36251881Speter
37251881Speter#include <errno.h>
38251881Speter#include <pthread.h>
39251881Speter#include <signal.h>
40251881Speter#include <stdio.h>
41251881Speter#include <string.h>
42251881Speter
43251881Speter#if defined(_LIBC_R_)
44251881Speter#include <pthread_np.h>
45251881Speter#endif
46251881Speter
47251881Speterstatic int		sigcounts[NSIG + 1];
48251881Speterstatic sigset_t		wait_mask;
49251881Speterstatic pthread_mutex_t	waiter_mutex;
50251881Speter
51251881Speter
52251881Speterstatic void *
53251881Spetersigwaiter (void *arg)
54251881Speter{
55251881Speter	int signo;
56251881Speter	sigset_t mask;
57251881Speter
58251881Speter	/* Block SIGHUP */
59251881Speter	sigemptyset (&mask);
60251881Speter	sigaddset (&mask, SIGHUP);
61251881Speter	sigprocmask (SIG_BLOCK, &mask, NULL);
62251881Speter
63251881Speter	while (sigcounts[SIGINT] == 0) {
64251881Speter		if (sigwait (&wait_mask, &signo) != 0) {
65251881Speter			fprintf (stderr,
66251881Speter			    "Unable to wait for signal, errno %d\n",
67251881Speter			    errno);
68251881Speter			exit (1);
69251881Speter		}
70251881Speter		sigcounts[signo]++;
71251881Speter		fprintf (stderr, "Sigwait caught signal %d\n", signo);
72251881Speter
73251881Speter		/* Allow the main thread to prevent the sigwait. */
74251881Speter		pthread_mutex_lock (&waiter_mutex);
75251881Speter		pthread_mutex_unlock (&waiter_mutex);
76251881Speter	}
77251881Speter
78251881Speter	pthread_exit (arg);
79251881Speter	return (NULL);
80251881Speter}
81251881Speter
82251881Speter
83251881Speterstatic void
84251881Spetersighandler (int signo)
85251881Speter{
86251881Speter	fprintf (stderr, "  -> Signal handler caught signal %d\n", signo);
87251881Speter
88251881Speter	if ((signo >= 0) && (signo <= NSIG))
89251881Speter		sigcounts[signo]++;
90251881Speter}
91251881Speter
92251881Speterstatic void
93251881Spetersend_thread_signal (pthread_t tid, int signo)
94251881Speter{
95251881Speter	if (pthread_kill (tid, signo) != 0) {
96251881Speter		fprintf (stderr, "Unable to send thread signal, errno %d.\n",
97251881Speter		    errno);
98251881Speter		exit (1);
99251881Speter	}
100251881Speter}
101251881Speter
102251881Speterstatic void
103251881Spetersend_process_signal (int signo)
104251881Speter{
105251881Speter	if (kill (getpid (), signo) != 0) {
106251881Speter		fprintf (stderr, "Unable to send process signal, errno %d.\n",
107251881Speter		    errno);
108251881Speter		exit (1);
109251881Speter	}
110251881Speter}
111251881Speter
112251881Speter
113251881Speterint main (int argc, char *argv[])
114251881Speter{
115251881Speter	pthread_mutexattr_t mattr;
116251881Speter	pthread_attr_t	pattr;
117251881Speter	pthread_t	tid;
118251881Speter	void *		exit_status;
119251881Speter	struct sigaction act;
120251881Speter
121251881Speter	/* Initialize our signal counts. */
122251881Speter	memset ((void *) sigcounts, 0, NSIG * sizeof (int));
123251881Speter
124251881Speter	/* Setup our wait mask. */
125251881Speter	sigemptyset (&wait_mask);		/* Default action	*/
126251881Speter	sigaddset (&wait_mask, SIGHUP);		/* terminate		*/
127251881Speter	sigaddset (&wait_mask, SIGINT);		/* terminate		*/
128251881Speter	sigaddset (&wait_mask, SIGQUIT);	/* create core image	*/
129251881Speter	sigaddset (&wait_mask, SIGURG);		/* ignore		*/
130251881Speter	sigaddset (&wait_mask, SIGIO);		/* ignore		*/
131251881Speter	sigaddset (&wait_mask, SIGUSR1);	/* terminate		*/
132251881Speter
133251881Speter	/* Ignore signals SIGHUP and SIGIO. */
134251881Speter	sigemptyset (&act.sa_mask);
135251881Speter	sigaddset (&act.sa_mask, SIGHUP);
136251881Speter	sigaddset (&act.sa_mask, SIGIO);
137251881Speter	act.sa_handler = SIG_IGN;
138251881Speter	act.sa_flags = 0;
139251881Speter	sigaction (SIGHUP, &act, NULL);
140251881Speter	sigaction (SIGIO, &act, NULL);
141251881Speter
142251881Speter	/* Install a signal handler for SIGURG */
143251881Speter	sigemptyset (&act.sa_mask);
144251881Speter	sigaddset (&act.sa_mask, SIGURG);
145251881Speter	act.sa_handler = sighandler;
146251881Speter	act.sa_flags = SA_RESTART;
147251881Speter	sigaction (SIGURG, &act, NULL);
148251881Speter
149251881Speter	/* Install a signal handler for SIGXCPU */
150251881Speter	sigemptyset (&act.sa_mask);
151251881Speter	sigaddset (&act.sa_mask, SIGXCPU);
152251881Speter	sigaction (SIGXCPU, &act, NULL);
153251881Speter
154251881Speter	/*
155251881Speter	 * Initialize the thread attribute.
156251881Speter	 */
157251881Speter	if ((pthread_attr_init (&pattr) != 0) ||
158251881Speter	    (pthread_attr_setdetachstate (&pattr,
159251881Speter	    PTHREAD_CREATE_JOINABLE) != 0)) {
160251881Speter		fprintf (stderr, "Unable to initialize thread attributes.\n");
161251881Speter		exit (1);
162251881Speter	}
163251881Speter
164251881Speter	/*
165251881Speter	 * Initialize and create a mutex.
166251881Speter	 */
167251881Speter	if ((pthread_mutexattr_init (&mattr) != 0) ||
168251881Speter	    (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
169251881Speter		fprintf (stderr, "Unable to create waiter mutex.\n");
170251881Speter		exit (1);
171251881Speter	}
172251881Speter
173251881Speter	/*
174251881Speter	 * Create the sigwaiter thread.
175251881Speter	 */
176251881Speter	if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
177251881Speter		fprintf (stderr, "Unable to create thread.\n");
178251881Speter		exit (1);
179251881Speter	}
180251881Speter#if defined(_LIBC_R_)
181251881Speter	pthread_set_name_np (tid, "sigwaiter");
182251881Speter#endif
183251881Speter
184251881Speter	/*
185251881Speter	 * Verify that an ignored signal doesn't cause a wakeup.
186251881Speter	 * We don't have a handler installed for SIGIO.
187251881Speter	 */
188251881Speter	send_thread_signal (tid, SIGIO);
189251881Speter	sleep (1);
190251881Speter	send_process_signal (SIGIO);
191251881Speter	sleep (1);
192251881Speter	if (sigcounts[SIGIO] != 0)
193251881Speter		fprintf (stderr,
194251881Speter		    "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
195251881Speter
196251881Speter	/*
197251881Speter	 * Verify that a signal with a default action of ignore, for
198251881Speter	 * which we have a signal handler installed, will release a sigwait.
199251881Speter	 */
200251881Speter	send_thread_signal (tid, SIGURG);
201251881Speter	sleep (1);
202251881Speter	send_process_signal (SIGURG);
203251881Speter	sleep (1);
204251881Speter	if (sigcounts[SIGURG] != 2)
205251881Speter		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
206251881Speter
207251881Speter	/*
208251881Speter	 * Verify that a signal with a default action that terminates
209251881Speter	 * the process will release a sigwait.
210251881Speter	 */
211251881Speter	send_thread_signal (tid, SIGUSR1);
212251881Speter	sleep (1);
213251881Speter	send_process_signal (SIGUSR1);
214251881Speter	sleep (1);
215251881Speter	if (sigcounts[SIGUSR1] != 2)
216251881Speter		fprintf (stderr,
217251881Speter		    "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
218251881Speter
219251881Speter	/*
220251881Speter	 * Verify that if we install a signal handler for a previously
221251881Speter	 * ignored signal, an occurrence of this signal will release
222251881Speter	 * the (already waiting) sigwait.
223251881Speter	 */
224251881Speter
225251881Speter	/* Install a signal handler for SIGHUP. */
226251881Speter	sigemptyset (&act.sa_mask);
227251881Speter	sigaddset (&act.sa_mask, SIGHUP);
228251881Speter	act.sa_handler = sighandler;
229251881Speter	act.sa_flags = SA_RESTART;
230251881Speter	sigaction (SIGHUP, &act, NULL);
231251881Speter
232251881Speter	/* Sending SIGHUP should release the sigwait. */
233251881Speter	send_process_signal (SIGHUP);
234251881Speter	sleep (1);
235251881Speter	send_thread_signal (tid, SIGHUP);
236251881Speter	sleep (1);
237251881Speter	if (sigcounts[SIGHUP] != 2)
238251881Speter		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
239251881Speter
240251881Speter	/*
241251881Speter	 * Verify that a pending signal in the waiters mask will
242251881Speter	 * cause sigwait to return the pending signal.  We do this
243251881Speter	 * by taking the waiters mutex and signaling the waiter to
244251881Speter	 * release him from the sigwait.  The waiter will block
245251881Speter	 * on taking the mutex, and we can then send the waiter a
246251881Speter	 * signal which should be added to his pending signals.
247251881Speter	 * The next time the waiter does a sigwait, he should
248251881Speter	 * return with the pending signal.
249251881Speter	 */
250251881Speter	sigcounts[SIGHUP] = 0;
251251881Speter 	pthread_mutex_lock (&waiter_mutex);
252251881Speter	/* Release the waiter from sigwait. */
253251881Speter	send_process_signal (SIGHUP);
254251881Speter	sleep (1);
255251881Speter	if (sigcounts[SIGHUP] != 1)
256251881Speter		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
257251881Speter	/*
258251881Speter	 * Add SIGHUP to the process pending signals.  Since there is
259251881Speter	 * a signal handler installed for SIGHUP and this signal is
260251881Speter	 * blocked from the waiter thread and unblocked in the main
261251881Speter	 * thread, the signal handler should be called once for SIGHUP.
262251881Speter	 */
263251881Speter	send_process_signal (SIGHUP);
264251881Speter	/* Release the waiter thread and allow him to run. */
265251881Speter	pthread_mutex_unlock (&waiter_mutex);
266251881Speter	sleep (1);
267251881Speter	if (sigcounts[SIGHUP] != 2)
268251881Speter		fprintf (stderr,
269251881Speter		    "FAIL: sigwait doesn't return for pending SIGHUP.\n");
270251881Speter
271251881Speter	/*
272251881Speter	 * Repeat the above test using pthread_kill and SIGUSR1.
273251881Speter	 */
274251881Speter	sigcounts[SIGUSR1] = 0;
275251881Speter 	pthread_mutex_lock (&waiter_mutex);
276251881Speter	/* Release the waiter from sigwait. */
277251881Speter	send_thread_signal (tid, SIGUSR1);
278251881Speter	sleep (1);
279251881Speter	if (sigcounts[SIGUSR1] != 1)
280251881Speter		fprintf (stderr,
281251881Speter		    "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
282251881Speter	/* Add SIGUSR1 to the waiters pending signals. */
283251881Speter	send_thread_signal (tid, SIGUSR1);
284251881Speter	/* Release the waiter thread and allow him to run. */
285251881Speter	pthread_mutex_unlock (&waiter_mutex);
286251881Speter	sleep (1);
287251881Speter	if (sigcounts[SIGUSR1] != 2)
288251881Speter		fprintf (stderr,
289251881Speter		    "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
290251881Speter
291251881Speter	/*
292251881Speter	 * Verify that we can still kill the process for a signal
293251881Speter	 * not being waited on by sigwait.
294251881Speter	 */
295251881Speter	send_process_signal (SIGPIPE);
296251881Speter	fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
297251881Speter
298251881Speter	/*
299251881Speter	 * Wait for the thread to finish.
300251881Speter	 */
301251881Speter	pthread_join (tid, &exit_status);
302251881Speter
303251881Speter	return (0);
304251881Speter}
305251881Speter