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