xref: /dflybsd-src/test/libpthread/sigwait_d.c (revision 624815385bcf105ef0d61ce7430127aa835132e7)
1e5a92d33SSascha Wildner /*
2e5a92d33SSascha Wildner  * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
3e5a92d33SSascha Wildner  * All rights reserved.
4e5a92d33SSascha Wildner  *
5e5a92d33SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6e5a92d33SSascha Wildner  * modification, are permitted provided that the following conditions
7e5a92d33SSascha Wildner  * are met:
8e5a92d33SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9e5a92d33SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10e5a92d33SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11e5a92d33SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12e5a92d33SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13e5a92d33SSascha Wildner  * 3. All advertising materials mentioning features or use of this software
14e5a92d33SSascha Wildner  *    must display the following acknowledgement:
15e5a92d33SSascha Wildner  *	This product includes software developed by Daniel M. Eischen.
16e5a92d33SSascha Wildner  * 4. Neither the name of the author nor the names of any co-contributors
17e5a92d33SSascha Wildner  *    may be used to endorse or promote products derived from this software
18e5a92d33SSascha Wildner  *    without specific prior written permission.
19e5a92d33SSascha Wildner  *
20e5a92d33SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
21e5a92d33SSascha Wildner  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22e5a92d33SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23e5a92d33SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24e5a92d33SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25e5a92d33SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26e5a92d33SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27e5a92d33SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28e5a92d33SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29e5a92d33SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30e5a92d33SSascha Wildner  * SUCH DAMAGE.
31e5a92d33SSascha Wildner  *
32e5a92d33SSascha Wildner  * $FreeBSD: src/lib/libc_r/test/sigwait_d.c,v 1.1.2.2 2001/06/22 21:44:27 jasone Exp $
33e5a92d33SSascha Wildner  */
34e5a92d33SSascha Wildner #include <stdlib.h>
35e5a92d33SSascha Wildner #include <unistd.h>
36e5a92d33SSascha Wildner 
37e5a92d33SSascha Wildner #include <errno.h>
38e5a92d33SSascha Wildner #include <pthread.h>
39*62481538SSascha Wildner #include <pthread_np.h>
40e5a92d33SSascha Wildner #include <signal.h>
41e5a92d33SSascha Wildner #include <stdio.h>
42e5a92d33SSascha Wildner #include <string.h>
43e5a92d33SSascha Wildner 
44e5a92d33SSascha Wildner static int		sigcounts[NSIG + 1];
45e5a92d33SSascha Wildner static sigset_t		wait_mask;
46e5a92d33SSascha Wildner static pthread_mutex_t	waiter_mutex;
47e5a92d33SSascha Wildner 
48e5a92d33SSascha Wildner 
49e5a92d33SSascha Wildner static void *
sigwaiter(void * arg)50e5a92d33SSascha Wildner sigwaiter (void *arg)
51e5a92d33SSascha Wildner {
52e5a92d33SSascha Wildner 	int signo;
53e5a92d33SSascha Wildner 	sigset_t mask;
54e5a92d33SSascha Wildner 
55e5a92d33SSascha Wildner 	/* Block SIGHUP */
56e5a92d33SSascha Wildner 	sigemptyset (&mask);
57e5a92d33SSascha Wildner 	sigaddset (&mask, SIGHUP);
58e5a92d33SSascha Wildner 	sigprocmask (SIG_BLOCK, &mask, NULL);
59e5a92d33SSascha Wildner 
60e5a92d33SSascha Wildner 	while (sigcounts[SIGINT] == 0) {
61e5a92d33SSascha Wildner 		if (sigwait (&wait_mask, &signo) != 0) {
62e5a92d33SSascha Wildner 			fprintf (stderr,
63e5a92d33SSascha Wildner 			    "Unable to wait for signal, errno %d\n",
64e5a92d33SSascha Wildner 			    errno);
65e5a92d33SSascha Wildner 			exit (1);
66e5a92d33SSascha Wildner 		}
67e5a92d33SSascha Wildner 		sigcounts[signo]++;
68e5a92d33SSascha Wildner 		fprintf (stderr, "Sigwait caught signal %d\n", signo);
69e5a92d33SSascha Wildner 
70e5a92d33SSascha Wildner 		/* Allow the main thread to prevent the sigwait. */
71e5a92d33SSascha Wildner 		pthread_mutex_lock (&waiter_mutex);
72e5a92d33SSascha Wildner 		pthread_mutex_unlock (&waiter_mutex);
73e5a92d33SSascha Wildner 	}
74e5a92d33SSascha Wildner 
75e5a92d33SSascha Wildner 	pthread_exit (arg);
76e5a92d33SSascha Wildner 	return (NULL);
77e5a92d33SSascha Wildner }
78e5a92d33SSascha Wildner 
79e5a92d33SSascha Wildner 
80e5a92d33SSascha Wildner static void
sighandler(int signo)81e5a92d33SSascha Wildner sighandler (int signo)
82e5a92d33SSascha Wildner {
83e5a92d33SSascha Wildner 	fprintf (stderr, "  -> Signal handler caught signal %d\n", signo);
84e5a92d33SSascha Wildner 
85e5a92d33SSascha Wildner 	if ((signo >= 0) && (signo <= NSIG))
86e5a92d33SSascha Wildner 		sigcounts[signo]++;
87e5a92d33SSascha Wildner }
88e5a92d33SSascha Wildner 
89e5a92d33SSascha Wildner static void
send_thread_signal(pthread_t tid,int signo)90e5a92d33SSascha Wildner send_thread_signal (pthread_t tid, int signo)
91e5a92d33SSascha Wildner {
92e5a92d33SSascha Wildner 	if (pthread_kill (tid, signo) != 0) {
93e5a92d33SSascha Wildner 		fprintf (stderr, "Unable to send thread signal, errno %d.\n",
94e5a92d33SSascha Wildner 		    errno);
95e5a92d33SSascha Wildner 		exit (1);
96e5a92d33SSascha Wildner 	}
97e5a92d33SSascha Wildner }
98e5a92d33SSascha Wildner 
99e5a92d33SSascha Wildner static void
send_process_signal(int signo)100e5a92d33SSascha Wildner send_process_signal (int signo)
101e5a92d33SSascha Wildner {
102e5a92d33SSascha Wildner 	if (kill (getpid (), signo) != 0) {
103e5a92d33SSascha Wildner 		fprintf (stderr, "Unable to send process signal, errno %d.\n",
104e5a92d33SSascha Wildner 		    errno);
105e5a92d33SSascha Wildner 		exit (1);
106e5a92d33SSascha Wildner 	}
107e5a92d33SSascha Wildner }
108e5a92d33SSascha Wildner 
109e5a92d33SSascha Wildner 
main(int argc,char * argv[])110e5a92d33SSascha Wildner int main (int argc, char *argv[])
111e5a92d33SSascha Wildner {
112e5a92d33SSascha Wildner 	pthread_mutexattr_t mattr;
113e5a92d33SSascha Wildner 	pthread_attr_t	pattr;
114e5a92d33SSascha Wildner 	pthread_t	tid;
115e5a92d33SSascha Wildner 	void *		exit_status;
116e5a92d33SSascha Wildner 	struct sigaction act;
117e5a92d33SSascha Wildner 
118e5a92d33SSascha Wildner 	/* Initialize our signal counts. */
119e5a92d33SSascha Wildner 	memset ((void *) sigcounts, 0, NSIG * sizeof (int));
120e5a92d33SSascha Wildner 
121e5a92d33SSascha Wildner 	/* Setup our wait mask. */
122e5a92d33SSascha Wildner 	sigemptyset (&wait_mask);		/* Default action	*/
123e5a92d33SSascha Wildner 	sigaddset (&wait_mask, SIGHUP);		/* terminate		*/
124e5a92d33SSascha Wildner 	sigaddset (&wait_mask, SIGINT);		/* terminate		*/
125e5a92d33SSascha Wildner 	sigaddset (&wait_mask, SIGQUIT);	/* create core image	*/
126e5a92d33SSascha Wildner 	sigaddset (&wait_mask, SIGURG);		/* ignore		*/
127e5a92d33SSascha Wildner 	sigaddset (&wait_mask, SIGIO);		/* ignore		*/
128e5a92d33SSascha Wildner 	sigaddset (&wait_mask, SIGUSR1);	/* terminate		*/
129e5a92d33SSascha Wildner 
130e5a92d33SSascha Wildner 	/* Ignore signals SIGHUP and SIGIO. */
131e5a92d33SSascha Wildner 	sigemptyset (&act.sa_mask);
132e5a92d33SSascha Wildner 	sigaddset (&act.sa_mask, SIGHUP);
133e5a92d33SSascha Wildner 	sigaddset (&act.sa_mask, SIGIO);
134e5a92d33SSascha Wildner 	act.sa_handler = SIG_IGN;
135e5a92d33SSascha Wildner 	act.sa_flags = 0;
136e5a92d33SSascha Wildner 	sigaction (SIGHUP, &act, NULL);
137e5a92d33SSascha Wildner 	sigaction (SIGIO, &act, NULL);
138e5a92d33SSascha Wildner 
139e5a92d33SSascha Wildner 	/* Install a signal handler for SIGURG */
140e5a92d33SSascha Wildner 	sigemptyset (&act.sa_mask);
141e5a92d33SSascha Wildner 	sigaddset (&act.sa_mask, SIGURG);
142e5a92d33SSascha Wildner 	act.sa_handler = sighandler;
143e5a92d33SSascha Wildner 	act.sa_flags = SA_RESTART;
144e5a92d33SSascha Wildner 	sigaction (SIGURG, &act, NULL);
145e5a92d33SSascha Wildner 
146e5a92d33SSascha Wildner 	/* Install a signal handler for SIGXCPU */
147e5a92d33SSascha Wildner 	sigemptyset (&act.sa_mask);
148e5a92d33SSascha Wildner 	sigaddset (&act.sa_mask, SIGXCPU);
149e5a92d33SSascha Wildner 	sigaction (SIGXCPU, &act, NULL);
150e5a92d33SSascha Wildner 
151e5a92d33SSascha Wildner 	/*
152e5a92d33SSascha Wildner 	 * Initialize the thread attribute.
153e5a92d33SSascha Wildner 	 */
154e5a92d33SSascha Wildner 	if ((pthread_attr_init (&pattr) != 0) ||
155e5a92d33SSascha Wildner 	    (pthread_attr_setdetachstate (&pattr,
156e5a92d33SSascha Wildner 	    PTHREAD_CREATE_JOINABLE) != 0)) {
157e5a92d33SSascha Wildner 		fprintf (stderr, "Unable to initialize thread attributes.\n");
158e5a92d33SSascha Wildner 		exit (1);
159e5a92d33SSascha Wildner 	}
160e5a92d33SSascha Wildner 
161e5a92d33SSascha Wildner 	/*
162e5a92d33SSascha Wildner 	 * Initialize and create a mutex.
163e5a92d33SSascha Wildner 	 */
164e5a92d33SSascha Wildner 	if ((pthread_mutexattr_init (&mattr) != 0) ||
165e5a92d33SSascha Wildner 	    (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
166e5a92d33SSascha Wildner 		fprintf (stderr, "Unable to create waiter mutex.\n");
167e5a92d33SSascha Wildner 		exit (1);
168e5a92d33SSascha Wildner 	}
169e5a92d33SSascha Wildner 
170e5a92d33SSascha Wildner 	/*
171e5a92d33SSascha Wildner 	 * Create the sigwaiter thread.
172e5a92d33SSascha Wildner 	 */
173e5a92d33SSascha Wildner 	if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
174e5a92d33SSascha Wildner 		fprintf (stderr, "Unable to create thread.\n");
175e5a92d33SSascha Wildner 		exit (1);
176e5a92d33SSascha Wildner 	}
177e5a92d33SSascha Wildner 	pthread_set_name_np (tid, "sigwaiter");
178e5a92d33SSascha Wildner 
179e5a92d33SSascha Wildner 	/*
180e5a92d33SSascha Wildner 	 * Verify that an ignored signal doesn't cause a wakeup.
181e5a92d33SSascha Wildner 	 * We don't have a handler installed for SIGIO.
182e5a92d33SSascha Wildner 	 */
183e5a92d33SSascha Wildner 	send_thread_signal (tid, SIGIO);
184e5a92d33SSascha Wildner 	sleep (1);
185e5a92d33SSascha Wildner 	send_process_signal (SIGIO);
186e5a92d33SSascha Wildner 	sleep (1);
187e5a92d33SSascha Wildner 	if (sigcounts[SIGIO] != 0)
188e5a92d33SSascha Wildner 		fprintf (stderr,
189e5a92d33SSascha Wildner 		    "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
190e5a92d33SSascha Wildner 
191e5a92d33SSascha Wildner 	/*
192e5a92d33SSascha Wildner 	 * Verify that a signal with a default action of ignore, for
193e5a92d33SSascha Wildner 	 * which we have a signal handler installed, will release a sigwait.
194e5a92d33SSascha Wildner 	 */
195e5a92d33SSascha Wildner 	send_thread_signal (tid, SIGURG);
196e5a92d33SSascha Wildner 	sleep (1);
197e5a92d33SSascha Wildner 	send_process_signal (SIGURG);
198e5a92d33SSascha Wildner 	sleep (1);
199e5a92d33SSascha Wildner 	if (sigcounts[SIGURG] != 2)
200e5a92d33SSascha Wildner 		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
201e5a92d33SSascha Wildner 
202e5a92d33SSascha Wildner 	/*
203e5a92d33SSascha Wildner 	 * Verify that a signal with a default action that terminates
204e5a92d33SSascha Wildner 	 * the process will release a sigwait.
205e5a92d33SSascha Wildner 	 */
206e5a92d33SSascha Wildner 	send_thread_signal (tid, SIGUSR1);
207e5a92d33SSascha Wildner 	sleep (1);
208e5a92d33SSascha Wildner 	send_process_signal (SIGUSR1);
209e5a92d33SSascha Wildner 	sleep (1);
210e5a92d33SSascha Wildner 	if (sigcounts[SIGUSR1] != 2)
211e5a92d33SSascha Wildner 		fprintf (stderr,
212e5a92d33SSascha Wildner 		    "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
213e5a92d33SSascha Wildner 
214e5a92d33SSascha Wildner 	/*
215e5a92d33SSascha Wildner 	 * Verify that if we install a signal handler for a previously
216e5a92d33SSascha Wildner 	 * ignored signal, an occurrence of this signal will release
217e5a92d33SSascha Wildner 	 * the (already waiting) sigwait.
218e5a92d33SSascha Wildner 	 */
219e5a92d33SSascha Wildner 
220e5a92d33SSascha Wildner 	/* Install a signal handler for SIGHUP. */
221e5a92d33SSascha Wildner 	sigemptyset (&act.sa_mask);
222e5a92d33SSascha Wildner 	sigaddset (&act.sa_mask, SIGHUP);
223e5a92d33SSascha Wildner 	act.sa_handler = sighandler;
224e5a92d33SSascha Wildner 	act.sa_flags = SA_RESTART;
225e5a92d33SSascha Wildner 	sigaction (SIGHUP, &act, NULL);
226e5a92d33SSascha Wildner 
227e5a92d33SSascha Wildner 	/* Sending SIGHUP should release the sigwait. */
228e5a92d33SSascha Wildner 	send_process_signal (SIGHUP);
229e5a92d33SSascha Wildner 	sleep (1);
230e5a92d33SSascha Wildner 	send_thread_signal (tid, SIGHUP);
231e5a92d33SSascha Wildner 	sleep (1);
232e5a92d33SSascha Wildner 	if (sigcounts[SIGHUP] != 2)
233e5a92d33SSascha Wildner 		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
234e5a92d33SSascha Wildner 
235e5a92d33SSascha Wildner 	/*
236e5a92d33SSascha Wildner 	 * Verify that a pending signal in the waiters mask will
237e5a92d33SSascha Wildner 	 * cause sigwait to return the pending signal.  We do this
238e5a92d33SSascha Wildner 	 * by taking the waiters mutex and signaling the waiter to
239e5a92d33SSascha Wildner 	 * release him from the sigwait.  The waiter will block
240e5a92d33SSascha Wildner 	 * on taking the mutex, and we can then send the waiter a
241e5a92d33SSascha Wildner 	 * signal which should be added to his pending signals.
242e5a92d33SSascha Wildner 	 * The next time the waiter does a sigwait, he should
243e5a92d33SSascha Wildner 	 * return with the pending signal.
244e5a92d33SSascha Wildner 	 */
245e5a92d33SSascha Wildner 	sigcounts[SIGHUP] = 0;
246e5a92d33SSascha Wildner  	pthread_mutex_lock (&waiter_mutex);
247e5a92d33SSascha Wildner 	/* Release the waiter from sigwait. */
248e5a92d33SSascha Wildner 	send_process_signal (SIGHUP);
249e5a92d33SSascha Wildner 	sleep (1);
250e5a92d33SSascha Wildner 	if (sigcounts[SIGHUP] != 1)
251e5a92d33SSascha Wildner 		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
252e5a92d33SSascha Wildner 	/*
253e5a92d33SSascha Wildner 	 * Add SIGHUP to the process pending signals.  Since there is
254e5a92d33SSascha Wildner 	 * a signal handler installed for SIGHUP and this signal is
255e5a92d33SSascha Wildner 	 * blocked from the waiter thread and unblocked in the main
256e5a92d33SSascha Wildner 	 * thread, the signal handler should be called once for SIGHUP.
257e5a92d33SSascha Wildner 	 */
258e5a92d33SSascha Wildner 	send_process_signal (SIGHUP);
259e5a92d33SSascha Wildner 	/* Release the waiter thread and allow him to run. */
260e5a92d33SSascha Wildner 	pthread_mutex_unlock (&waiter_mutex);
261e5a92d33SSascha Wildner 	sleep (1);
262e5a92d33SSascha Wildner 	if (sigcounts[SIGHUP] != 2)
263e5a92d33SSascha Wildner 		fprintf (stderr,
264e5a92d33SSascha Wildner 		    "FAIL: sigwait doesn't return for pending SIGHUP.\n");
265e5a92d33SSascha Wildner 
266e5a92d33SSascha Wildner 	/*
267e5a92d33SSascha Wildner 	 * Repeat the above test using pthread_kill and SIGUSR1.
268e5a92d33SSascha Wildner 	 */
269e5a92d33SSascha Wildner 	sigcounts[SIGUSR1] = 0;
270e5a92d33SSascha Wildner  	pthread_mutex_lock (&waiter_mutex);
271e5a92d33SSascha Wildner 	/* Release the waiter from sigwait. */
272e5a92d33SSascha Wildner 	send_thread_signal (tid, SIGUSR1);
273e5a92d33SSascha Wildner 	sleep (1);
274e5a92d33SSascha Wildner 	if (sigcounts[SIGUSR1] != 1)
275e5a92d33SSascha Wildner 		fprintf (stderr,
276e5a92d33SSascha Wildner 		    "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
277e5a92d33SSascha Wildner 	/* Add SIGUSR1 to the waiters pending signals. */
278e5a92d33SSascha Wildner 	send_thread_signal (tid, SIGUSR1);
279e5a92d33SSascha Wildner 	/* Release the waiter thread and allow him to run. */
280e5a92d33SSascha Wildner 	pthread_mutex_unlock (&waiter_mutex);
281e5a92d33SSascha Wildner 	sleep (1);
282e5a92d33SSascha Wildner 	if (sigcounts[SIGUSR1] != 2)
283e5a92d33SSascha Wildner 		fprintf (stderr,
284e5a92d33SSascha Wildner 		    "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
285e5a92d33SSascha Wildner 
286e5a92d33SSascha Wildner 	/*
287e5a92d33SSascha Wildner 	 * Verify that we can still kill the process for a signal
288e5a92d33SSascha Wildner 	 * not being waited on by sigwait.
289e5a92d33SSascha Wildner 	 */
290e5a92d33SSascha Wildner 	send_process_signal (SIGPIPE);
291e5a92d33SSascha Wildner 	fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
292e5a92d33SSascha Wildner 
293e5a92d33SSascha Wildner 	/*
294e5a92d33SSascha Wildner 	 * Wait for the thread to finish.
295e5a92d33SSascha Wildner 	 */
296e5a92d33SSascha Wildner 	pthread_join (tid, &exit_status);
297e5a92d33SSascha Wildner 
298e5a92d33SSascha Wildner 	return (0);
299e5a92d33SSascha Wildner }
300