xref: /dragonfly/test/libpthread/sigwait_d.c (revision 624815385bcf105ef0d61ce7430127aa835132e7)
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