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