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