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 * 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 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 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