1 /* $OpenBSD: sigsuspend.c,v 1.2 2001/11/11 23:26:35 deraadt 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 74 while (sigcounts[SIGINT] == 0) { 75 save_count = sigcounts[SIGUSR2]; 76 77 status = sigsuspend (&suspender_mask); 78 if ((status == 0) || (errno != EINTR)) { 79 DIE(errno, "Unable to suspend for signals, " 80 "return value %d\n", 81 status); 82 } 83 for (i = 0; i < fifo_depth; i++) 84 printf ("Sigsuspend woke up by signal %d (%s)\n", 85 sigfifo[i], strsignal(sigfifo[i])); 86 fifo_depth = 0; 87 } 88 89 return (arg); 90 } 91 92 93 static void 94 sighandler (int signo) 95 { 96 int save_errno = errno; 97 char buf[8192]; 98 sigset_t set; 99 pthread_t self; 100 101 if ((signo >= 0) && (signo <= NSIG)) 102 sigcounts[signo]++; 103 104 /* 105 * If we are running on behalf of the suspender thread, 106 * ensure that we have the correct mask set. 107 */ 108 self = pthread_self (); 109 if (self == suspender_tid) { 110 sigfifo[fifo_depth] = signo; 111 fifo_depth++; 112 snprintf(buf, sizeof buf, 113 " -> Suspender thread signal handler caught " 114 "signal %d (%s)\n", signo, strsignal(signo)); 115 write(STDOUT_FILENO, buf, strlen(buf)); 116 sigprocmask (SIG_SETMASK, NULL, &set); 117 ASSERT(set == suspender_mask); 118 } else { 119 snprintf(buf, sizeof buf, 120 " -> Main thread signal handler caught " 121 "signal %d (%s)\n", signo, strsignal(signo)); 122 write(STDOUT_FILENO, buf, strlen(buf)); 123 } 124 errno = save_errno; 125 } 126 127 128 int main (int argc, char *argv[]) 129 { 130 pthread_attr_t pattr; 131 struct sigaction act; 132 sigset_t oldset; 133 sigset_t newset; 134 135 /* Initialize our signal counts. */ 136 memset ((void *) sigcounts, 0, NSIG * sizeof (int)); 137 138 /* Ignore signal SIGIO. */ 139 sigemptyset (&act.sa_mask); 140 sigaddset (&act.sa_mask, SIGIO); 141 act.sa_handler = SIG_IGN; 142 act.sa_flags = 0; 143 CHECKe(sigaction (SIGIO, &act, NULL)); 144 145 /* Install a signal handler for SIGURG. */ 146 sigemptyset (&act.sa_mask); 147 sigaddset (&act.sa_mask, SIGURG); 148 act.sa_handler = sighandler; 149 act.sa_flags = SA_RESTART; 150 CHECKe(sigaction (SIGURG, &act, NULL)); 151 152 /* Install a signal handler for SIGXCPU */ 153 sigemptyset (&act.sa_mask); 154 sigaddset (&act.sa_mask, SIGXCPU); 155 CHECKe(sigaction (SIGXCPU, &act, NULL)); 156 157 /* Get our current signal mask. */ 158 CHECKe(sigprocmask (SIG_SETMASK, NULL, &oldset)); 159 160 /* Mask out SIGUSR1 and SIGUSR2. */ 161 newset = oldset; 162 sigaddset (&newset, SIGUSR1); 163 sigaddset (&newset, SIGUSR2); 164 CHECKe(sigprocmask (SIG_SETMASK, &newset, NULL)); 165 166 /* Install a signal handler for SIGUSR1 and SIGUSR2 */ 167 sigemptyset (&act.sa_mask); 168 sigaddset (&act.sa_mask, SIGUSR1); 169 sigaddset (&act.sa_mask, SIGUSR2); 170 act.sa_handler = sighandler; 171 act.sa_flags = SA_RESTART; 172 CHECKe(sigaction (SIGUSR1, &act, NULL)); 173 CHECKe(sigaction (SIGUSR2, &act, NULL)); 174 175 /* 176 * Initialize the thread attribute. 177 */ 178 CHECKr(pthread_attr_init (&pattr)); 179 CHECKr(pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE)); 180 181 /* 182 * Create the sigsuspender thread. 183 */ 184 CHECKr(pthread_create (&suspender_tid, &pattr, sigsuspender, NULL)); 185 186 /* 187 * Verify that an ignored signal doesn't cause a wakeup. 188 * We don't have a handler installed for SIGIO. 189 */ 190 CHECKr(pthread_kill (suspender_tid, SIGIO)); 191 sleep (1); 192 CHECKe(kill (getpid (), SIGIO)); 193 sleep (1); 194 /* sigsuspend should not wake up for ignored signal SIGIO */ 195 ASSERT(sigcounts[SIGIO] == 0); 196 197 /* 198 * Verify that a signal with a default action of ignore, for 199 * which we have a signal handler installed, will release a 200 * sigsuspend. 201 */ 202 CHECKr(pthread_kill (suspender_tid, SIGURG)); 203 sleep (1); 204 CHECKe(kill (getpid (), SIGURG)); 205 sleep (1); 206 /* sigsuspend should wake up for SIGURG */ 207 ASSERT(sigcounts[SIGURG] == 3); 208 209 /* 210 * Verify that a SIGUSR2 signal will release a sigsuspended 211 * thread. 212 */ 213 CHECKr(pthread_kill (suspender_tid, SIGUSR2)); 214 sleep (1); 215 CHECKe(kill (getpid (), SIGUSR2)); 216 sleep (1); 217 /* sigsuspend should wake yp for SIGUSR2 */ 218 ASSERT(sigcounts[SIGUSR2] == 2); 219 220 /* 221 * Verify that a signal, blocked in both the main and 222 * sigsuspender threads, does not cause the signal handler 223 * to be called. 224 */ 225 CHECKr(pthread_kill (suspender_tid, SIGUSR1)); 226 sleep (1); 227 CHECKe(kill (getpid (), SIGUSR1)); 228 sleep (1); 229 /* signal handler should not be called for USR1 */ 230 ASSERT(sigcounts[SIGUSR1] == 0); 231 #if 0 232 /* 233 * Verify that we can still kill the process for a signal 234 * not being waited on by sigwait. 235 */ 236 CHECKe(kill (getpid (), SIGPIPE)); 237 PANIC("SIGPIPE did not terminate process"); 238 239 /* 240 * Wait for the thread to finish. 241 */ 242 CHECKr(pthread_join (suspender_tid, NULL)); 243 #endif 244 SUCCEED; 245 } 246 247