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