1 /* $OpenBSD: sigsuspend.c,v 1.5 2012/02/20 01:51:32 guenther Exp $ */
2 /*
3 * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Daniel M. Eischen.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
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 #include <pthread_np.h>
44 #include "test.h"
45
46 static int sigcounts[NSIG + 1];
47 static int sigfifo[NSIG + 1];
48 static int fifo_depth = 0;
49 static sigset_t suspender_mask;
50 static pthread_t suspender_tid;
51
52
53 static void *
sigsuspender(void * arg)54 sigsuspender (void *arg)
55 {
56 int save_count, status, i;
57 sigset_t run_mask;
58
59 SET_NAME("sigsuspender");
60
61 /* Run with all signals blocked. */
62 sigfillset (&run_mask);
63 CHECKe(sigprocmask (SIG_SETMASK, &run_mask, NULL));
64
65 /* Allow these signals to wake us up during a sigsuspend. */
66 sigfillset (&suspender_mask); /* Default action */
67 sigdelset (&suspender_mask, SIGINT); /* terminate */
68 sigdelset (&suspender_mask, SIGHUP); /* terminate */
69 sigdelset (&suspender_mask, SIGQUIT); /* create core image */
70 sigdelset (&suspender_mask, SIGURG); /* ignore */
71 sigdelset (&suspender_mask, SIGIO); /* ignore */
72 sigdelset (&suspender_mask, SIGUSR2); /* terminate */
73 sigdelset (&suspender_mask, SIGSTOP); /* unblockable */
74 sigdelset (&suspender_mask, SIGKILL); /* unblockable */
75
76 while (sigcounts[SIGINT] == 0) {
77 save_count = sigcounts[SIGUSR2];
78
79 status = sigsuspend (&suspender_mask);
80 if ((status == 0) || (errno != EINTR)) {
81 DIE(errno, "Unable to suspend for signals, "
82 "return value %d\n",
83 status);
84 }
85 for (i = 0; i < fifo_depth; i++)
86 printf ("Sigsuspend woke up by signal %d (%s)\n",
87 sigfifo[i], strsignal(sigfifo[i]));
88 fifo_depth = 0;
89 }
90
91 return (arg);
92 }
93
94
95 static void
sighandler(int signo)96 sighandler (int signo)
97 {
98 int save_errno = errno;
99 char buf[8192];
100 sigset_t set;
101 sigset_t tmp;
102 pthread_t self;
103
104 if ((signo >= 0) && (signo <= NSIG))
105 sigcounts[signo]++;
106
107 /*
108 * If we are running on behalf of the suspender thread,
109 * ensure that we have the correct mask set. NOTE: per
110 * POSIX the current signo will be part of the mask unless
111 * SA_NODEFER was specified. Since it isn't in this test
112 * add the current signal to the original suspender_mask
113 * before checking.
114 */
115 self = pthread_self ();
116 if (self == suspender_tid) {
117 sigfifo[fifo_depth] = signo;
118 fifo_depth++;
119 snprintf(buf, sizeof buf,
120 " -> Suspender thread signal handler caught "
121 "signal %d (%s)\n", signo, strsignal(signo));
122 write(STDOUT_FILENO, buf, strlen(buf));
123 sigprocmask (SIG_SETMASK, NULL, &set);
124 tmp = suspender_mask;
125 sigaddset(&tmp, signo);
126 sigdelset(&tmp, SIGTHR);
127 sigdelset(&set, SIGTHR);
128 ASSERT(set == tmp);
129 } else {
130 snprintf(buf, sizeof buf,
131 " -> Main thread signal handler caught "
132 "signal %d (%s)\n", signo, strsignal(signo));
133 write(STDOUT_FILENO, buf, strlen(buf));
134 }
135 errno = save_errno;
136 }
137
138
main(int argc,char * argv[])139 int main (int argc, char *argv[])
140 {
141 pthread_attr_t pattr;
142 struct sigaction act;
143 sigset_t oldset;
144 sigset_t newset;
145
146 /* Initialize our signal counts. */
147 memset ((void *) sigcounts, 0, NSIG * sizeof (int));
148
149 /* Ignore signal SIGIO. */
150 sigemptyset (&act.sa_mask);
151 sigaddset (&act.sa_mask, SIGIO);
152 act.sa_handler = SIG_IGN;
153 act.sa_flags = 0;
154 CHECKe(sigaction (SIGIO, &act, NULL));
155
156 /* Install a signal handler for SIGURG. */
157 sigemptyset (&act.sa_mask);
158 sigaddset (&act.sa_mask, SIGURG);
159 act.sa_handler = sighandler;
160 act.sa_flags = SA_RESTART;
161 CHECKe(sigaction (SIGURG, &act, NULL));
162
163 /* Install a signal handler for SIGXCPU */
164 sigemptyset (&act.sa_mask);
165 sigaddset (&act.sa_mask, SIGXCPU);
166 CHECKe(sigaction (SIGXCPU, &act, NULL));
167
168 /* Get our current signal mask. */
169 CHECKe(sigprocmask (SIG_SETMASK, NULL, &oldset));
170
171 /* Mask out SIGUSR1 and SIGUSR2. */
172 newset = oldset;
173 sigaddset (&newset, SIGUSR1);
174 sigaddset (&newset, SIGUSR2);
175 CHECKe(sigprocmask (SIG_SETMASK, &newset, NULL));
176
177 /* Install a signal handler for SIGUSR1 and SIGUSR2 */
178 sigemptyset (&act.sa_mask);
179 sigaddset (&act.sa_mask, SIGUSR1);
180 sigaddset (&act.sa_mask, SIGUSR2);
181 act.sa_handler = sighandler;
182 act.sa_flags = SA_RESTART;
183 CHECKe(sigaction (SIGUSR1, &act, NULL));
184 CHECKe(sigaction (SIGUSR2, &act, NULL));
185
186 /*
187 * Initialize the thread attribute.
188 */
189 CHECKr(pthread_attr_init (&pattr));
190 CHECKr(pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE));
191
192 /*
193 * Create the sigsuspender thread.
194 */
195 CHECKr(pthread_create (&suspender_tid, &pattr, sigsuspender, NULL));
196
197 /*
198 * Verify that an ignored signal doesn't cause a wakeup.
199 * We don't have a handler installed for SIGIO.
200 */
201 CHECKr(pthread_kill (suspender_tid, SIGIO));
202 sleep (1);
203 CHECKe(kill (getpid (), SIGIO));
204 sleep (1);
205 /* sigsuspend should not wake up for ignored signal SIGIO */
206 ASSERT(sigcounts[SIGIO] == 0);
207
208 /*
209 * Verify that a signal with a default action of ignore, for
210 * which we have a signal handler installed, will release a
211 * sigsuspend.
212 */
213 CHECKr(pthread_kill (suspender_tid, SIGURG));
214 sleep (1);
215 CHECKe(kill (getpid (), SIGURG));
216 sleep (1);
217 /* sigsuspend should wake up for SIGURG */
218 ASSERT(sigcounts[SIGURG] == 2);
219
220 /*
221 * Verify that a SIGUSR2 signal will release a sigsuspended
222 * thread.
223 */
224 CHECKr(pthread_kill (suspender_tid, SIGUSR2));
225 sleep (1);
226 CHECKe(kill (getpid (), SIGUSR2));
227 sleep (1);
228 /* sigsuspend should wake up for SIGUSR2 */
229 ASSERT(sigcounts[SIGUSR2] == 2);
230
231 /*
232 * Verify that a signal, blocked in both the main and
233 * sigsuspender threads, does not cause the signal handler
234 * to be called.
235 */
236 CHECKr(pthread_kill (suspender_tid, SIGUSR1));
237 sleep (1);
238 CHECKe(kill (getpid (), SIGUSR1));
239 sleep (1);
240 /* signal handler should not be called for USR1 */
241 ASSERT(sigcounts[SIGUSR1] == 0);
242 #if 0
243 /*
244 * Verify that we can still kill the process for a signal
245 * not being waited on by sigwait.
246 */
247 CHECKe(kill (getpid (), SIGPIPE));
248 PANIC("SIGPIPE did not terminate process");
249
250 /*
251 * Wait for the thread to finish.
252 */
253 CHECKr(pthread_join (suspender_tid, NULL));
254 #endif
255 SUCCEED;
256 }
257
258