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$
33 */
34 #include <stdlib.h>
35 #include <unistd.h>
36
37 #include <errno.h>
38 #include <pthread.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <string.h>
42
43 #if defined(_LIBC_R_)
44 #include <pthread_np.h>
45 #endif
46
47 static int sigcounts[NSIG + 1];
48 static sigset_t wait_mask;
49 static pthread_mutex_t waiter_mutex;
50
51
52 static void *
sigwaiter(void * arg)53 sigwaiter (void *arg)
54 {
55 int signo;
56 sigset_t mask;
57
58 /* Block SIGHUP */
59 sigemptyset (&mask);
60 sigaddset (&mask, SIGHUP);
61 sigprocmask (SIG_BLOCK, &mask, NULL);
62
63 while (sigcounts[SIGINT] == 0) {
64 if (sigwait (&wait_mask, &signo) != 0) {
65 fprintf (stderr,
66 "Unable to wait for signal, errno %d\n",
67 errno);
68 exit (1);
69 }
70 sigcounts[signo]++;
71 fprintf (stderr, "Sigwait caught signal %d\n", signo);
72
73 /* Allow the main thread to prevent the sigwait. */
74 pthread_mutex_lock (&waiter_mutex);
75 pthread_mutex_unlock (&waiter_mutex);
76 }
77
78 pthread_exit (arg);
79 return (NULL);
80 }
81
82
83 static void
sighandler(int signo)84 sighandler (int signo)
85 {
86 fprintf (stderr, " -> Signal handler caught signal %d\n", signo);
87
88 if ((signo >= 0) && (signo <= NSIG))
89 sigcounts[signo]++;
90 }
91
92 static void
send_thread_signal(pthread_t tid,int signo)93 send_thread_signal (pthread_t tid, int signo)
94 {
95 if (pthread_kill (tid, signo) != 0) {
96 fprintf (stderr, "Unable to send thread signal, errno %d.\n",
97 errno);
98 exit (1);
99 }
100 }
101
102 static void
send_process_signal(int signo)103 send_process_signal (int signo)
104 {
105 if (kill (getpid (), signo) != 0) {
106 fprintf (stderr, "Unable to send process signal, errno %d.\n",
107 errno);
108 exit (1);
109 }
110 }
111
112
main(int argc,char * argv[])113 int main (int argc, char *argv[])
114 {
115 pthread_mutexattr_t mattr;
116 pthread_attr_t pattr;
117 pthread_t tid;
118 void * exit_status;
119 struct sigaction act;
120
121 /* Initialize our signal counts. */
122 memset ((void *) sigcounts, 0, NSIG * sizeof (int));
123
124 /* Setup our wait mask. */
125 sigemptyset (&wait_mask); /* Default action */
126 sigaddset (&wait_mask, SIGHUP); /* terminate */
127 sigaddset (&wait_mask, SIGINT); /* terminate */
128 sigaddset (&wait_mask, SIGQUIT); /* create core image */
129 sigaddset (&wait_mask, SIGURG); /* ignore */
130 sigaddset (&wait_mask, SIGIO); /* ignore */
131 sigaddset (&wait_mask, SIGUSR1); /* terminate */
132
133 /* Ignore signals SIGHUP and SIGIO. */
134 sigemptyset (&act.sa_mask);
135 sigaddset (&act.sa_mask, SIGHUP);
136 sigaddset (&act.sa_mask, SIGIO);
137 act.sa_handler = SIG_IGN;
138 act.sa_flags = 0;
139 sigaction (SIGHUP, &act, NULL);
140 sigaction (SIGIO, &act, NULL);
141
142 /* Install a signal handler for SIGURG */
143 sigemptyset (&act.sa_mask);
144 sigaddset (&act.sa_mask, SIGURG);
145 act.sa_handler = sighandler;
146 act.sa_flags = SA_RESTART;
147 sigaction (SIGURG, &act, NULL);
148
149 /* Install a signal handler for SIGXCPU */
150 sigemptyset (&act.sa_mask);
151 sigaddset (&act.sa_mask, SIGXCPU);
152 sigaction (SIGXCPU, &act, NULL);
153
154 /*
155 * Initialize the thread attribute.
156 */
157 if ((pthread_attr_init (&pattr) != 0) ||
158 (pthread_attr_setdetachstate (&pattr,
159 PTHREAD_CREATE_JOINABLE) != 0)) {
160 fprintf (stderr, "Unable to initialize thread attributes.\n");
161 exit (1);
162 }
163
164 /*
165 * Initialize and create a mutex.
166 */
167 if ((pthread_mutexattr_init (&mattr) != 0) ||
168 (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
169 fprintf (stderr, "Unable to create waiter mutex.\n");
170 exit (1);
171 }
172
173 /*
174 * Create the sigwaiter thread.
175 */
176 if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
177 fprintf (stderr, "Unable to create thread.\n");
178 exit (1);
179 }
180 #if defined(_LIBC_R_)
181 pthread_set_name_np (tid, "sigwaiter");
182 #endif
183
184 /*
185 * Verify that an ignored signal doesn't cause a wakeup.
186 * We don't have a handler installed for SIGIO.
187 */
188 send_thread_signal (tid, SIGIO);
189 sleep (1);
190 send_process_signal (SIGIO);
191 sleep (1);
192 if (sigcounts[SIGIO] != 0)
193 fprintf (stderr,
194 "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
195
196 /*
197 * Verify that a signal with a default action of ignore, for
198 * which we have a signal handler installed, will release a sigwait.
199 */
200 send_thread_signal (tid, SIGURG);
201 sleep (1);
202 send_process_signal (SIGURG);
203 sleep (1);
204 if (sigcounts[SIGURG] != 2)
205 fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
206
207 /*
208 * Verify that a signal with a default action that terminates
209 * the process will release a sigwait.
210 */
211 send_thread_signal (tid, SIGUSR1);
212 sleep (1);
213 send_process_signal (SIGUSR1);
214 sleep (1);
215 if (sigcounts[SIGUSR1] != 2)
216 fprintf (stderr,
217 "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
218
219 /*
220 * Verify that if we install a signal handler for a previously
221 * ignored signal, an occurrence of this signal will release
222 * the (already waiting) sigwait.
223 */
224
225 /* Install a signal handler for SIGHUP. */
226 sigemptyset (&act.sa_mask);
227 sigaddset (&act.sa_mask, SIGHUP);
228 act.sa_handler = sighandler;
229 act.sa_flags = SA_RESTART;
230 sigaction (SIGHUP, &act, NULL);
231
232 /* Sending SIGHUP should release the sigwait. */
233 send_process_signal (SIGHUP);
234 sleep (1);
235 send_thread_signal (tid, SIGHUP);
236 sleep (1);
237 if (sigcounts[SIGHUP] != 2)
238 fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
239
240 /*
241 * Verify that a pending signal in the waiters mask will
242 * cause sigwait to return the pending signal. We do this
243 * by taking the waiters mutex and signaling the waiter to
244 * release him from the sigwait. The waiter will block
245 * on taking the mutex, and we can then send the waiter a
246 * signal which should be added to his pending signals.
247 * The next time the waiter does a sigwait, he should
248 * return with the pending signal.
249 */
250 sigcounts[SIGHUP] = 0;
251 pthread_mutex_lock (&waiter_mutex);
252 /* Release the waiter from sigwait. */
253 send_process_signal (SIGHUP);
254 sleep (1);
255 if (sigcounts[SIGHUP] != 1)
256 fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
257 /*
258 * Add SIGHUP to the process pending signals. Since there is
259 * a signal handler installed for SIGHUP and this signal is
260 * blocked from the waiter thread and unblocked in the main
261 * thread, the signal handler should be called once for SIGHUP.
262 */
263 send_process_signal (SIGHUP);
264 /* Release the waiter thread and allow him to run. */
265 pthread_mutex_unlock (&waiter_mutex);
266 sleep (1);
267 if (sigcounts[SIGHUP] != 2)
268 fprintf (stderr,
269 "FAIL: sigwait doesn't return for pending SIGHUP.\n");
270
271 /*
272 * Repeat the above test using pthread_kill and SIGUSR1.
273 */
274 sigcounts[SIGUSR1] = 0;
275 pthread_mutex_lock (&waiter_mutex);
276 /* Release the waiter from sigwait. */
277 send_thread_signal (tid, SIGUSR1);
278 sleep (1);
279 if (sigcounts[SIGUSR1] != 1)
280 fprintf (stderr,
281 "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
282 /* Add SIGUSR1 to the waiters pending signals. */
283 send_thread_signal (tid, SIGUSR1);
284 /* Release the waiter thread and allow him to run. */
285 pthread_mutex_unlock (&waiter_mutex);
286 sleep (1);
287 if (sigcounts[SIGUSR1] != 2)
288 fprintf (stderr,
289 "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
290
291 /*
292 * Verify that we can still kill the process for a signal
293 * not being waited on by sigwait.
294 */
295 send_process_signal (SIGPIPE);
296 fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
297
298 /*
299 * Wait for the thread to finish.
300 */
301 pthread_join (tid, &exit_status);
302
303 return (0);
304 }
305