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