1251881Speter/* 2251881Speter * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> 3251881Speter * All rights reserved. 4251881Speter * 5251881Speter * Redistribution and use in source and binary forms, with or without 6251881Speter * modification, are permitted provided that the following conditions 7251881Speter * are met: 8251881Speter * 1. Redistributions of source code must retain the above copyright 9251881Speter * notice, this list of conditions and the following disclaimer. 10251881Speter * 2. Redistributions in binary form must reproduce the above copyright 11251881Speter * notice, this list of conditions and the following disclaimer in the 12251881Speter * documentation and/or other materials provided with the distribution. 13251881Speter * 3. All advertising materials mentioning features or use of this software 14251881Speter * must display the following acknowledgement: 15251881Speter * This product includes software developed by Daniel M. Eischen. 16251881Speter * 4. Neither the name of the author nor the names of any co-contributors 17251881Speter * may be used to endorse or promote products derived from this software 18251881Speter * without specific prior written permission. 19251881Speter * 20251881Speter * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS'' 21251881Speter * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30251881Speter * SUCH DAMAGE. 31251881Speter * 32251881Speter * $FreeBSD$ 33251881Speter */ 34251881Speter#include <stdlib.h> 35251881Speter#include <unistd.h> 36251881Speter 37251881Speter#include <errno.h> 38251881Speter#include <pthread.h> 39251881Speter#include <signal.h> 40251881Speter#include <stdio.h> 41251881Speter#include <string.h> 42251881Speter 43251881Speter#if defined(_LIBC_R_) 44251881Speter#include <pthread_np.h> 45251881Speter#endif 46251881Speter 47251881Speterstatic int sigcounts[NSIG + 1]; 48251881Speterstatic sigset_t wait_mask; 49251881Speterstatic pthread_mutex_t waiter_mutex; 50251881Speter 51251881Speter 52251881Speterstatic void * 53251881Spetersigwaiter (void *arg) 54251881Speter{ 55251881Speter int signo; 56251881Speter sigset_t mask; 57251881Speter 58251881Speter /* Block SIGHUP */ 59251881Speter sigemptyset (&mask); 60251881Speter sigaddset (&mask, SIGHUP); 61251881Speter sigprocmask (SIG_BLOCK, &mask, NULL); 62251881Speter 63251881Speter while (sigcounts[SIGINT] == 0) { 64251881Speter if (sigwait (&wait_mask, &signo) != 0) { 65251881Speter fprintf (stderr, 66251881Speter "Unable to wait for signal, errno %d\n", 67251881Speter errno); 68251881Speter exit (1); 69251881Speter } 70251881Speter sigcounts[signo]++; 71251881Speter fprintf (stderr, "Sigwait caught signal %d\n", signo); 72251881Speter 73251881Speter /* Allow the main thread to prevent the sigwait. */ 74251881Speter pthread_mutex_lock (&waiter_mutex); 75251881Speter pthread_mutex_unlock (&waiter_mutex); 76251881Speter } 77251881Speter 78251881Speter pthread_exit (arg); 79251881Speter return (NULL); 80251881Speter} 81251881Speter 82251881Speter 83251881Speterstatic void 84251881Spetersighandler (int signo) 85251881Speter{ 86251881Speter fprintf (stderr, " -> Signal handler caught signal %d\n", signo); 87251881Speter 88251881Speter if ((signo >= 0) && (signo <= NSIG)) 89251881Speter sigcounts[signo]++; 90251881Speter} 91251881Speter 92251881Speterstatic void 93251881Spetersend_thread_signal (pthread_t tid, int signo) 94251881Speter{ 95251881Speter if (pthread_kill (tid, signo) != 0) { 96251881Speter fprintf (stderr, "Unable to send thread signal, errno %d.\n", 97251881Speter errno); 98251881Speter exit (1); 99251881Speter } 100251881Speter} 101251881Speter 102251881Speterstatic void 103251881Spetersend_process_signal (int signo) 104251881Speter{ 105251881Speter if (kill (getpid (), signo) != 0) { 106251881Speter fprintf (stderr, "Unable to send process signal, errno %d.\n", 107251881Speter errno); 108251881Speter exit (1); 109251881Speter } 110251881Speter} 111251881Speter 112251881Speter 113251881Speterint main (int argc, char *argv[]) 114251881Speter{ 115251881Speter pthread_mutexattr_t mattr; 116251881Speter pthread_attr_t pattr; 117251881Speter pthread_t tid; 118251881Speter void * exit_status; 119251881Speter struct sigaction act; 120251881Speter 121251881Speter /* Initialize our signal counts. */ 122251881Speter memset ((void *) sigcounts, 0, NSIG * sizeof (int)); 123251881Speter 124251881Speter /* Setup our wait mask. */ 125251881Speter sigemptyset (&wait_mask); /* Default action */ 126251881Speter sigaddset (&wait_mask, SIGHUP); /* terminate */ 127251881Speter sigaddset (&wait_mask, SIGINT); /* terminate */ 128251881Speter sigaddset (&wait_mask, SIGQUIT); /* create core image */ 129251881Speter sigaddset (&wait_mask, SIGURG); /* ignore */ 130251881Speter sigaddset (&wait_mask, SIGIO); /* ignore */ 131251881Speter sigaddset (&wait_mask, SIGUSR1); /* terminate */ 132251881Speter 133251881Speter /* Ignore signals SIGHUP and SIGIO. */ 134251881Speter sigemptyset (&act.sa_mask); 135251881Speter sigaddset (&act.sa_mask, SIGHUP); 136251881Speter sigaddset (&act.sa_mask, SIGIO); 137251881Speter act.sa_handler = SIG_IGN; 138251881Speter act.sa_flags = 0; 139251881Speter sigaction (SIGHUP, &act, NULL); 140251881Speter sigaction (SIGIO, &act, NULL); 141251881Speter 142251881Speter /* Install a signal handler for SIGURG */ 143251881Speter sigemptyset (&act.sa_mask); 144251881Speter sigaddset (&act.sa_mask, SIGURG); 145251881Speter act.sa_handler = sighandler; 146251881Speter act.sa_flags = SA_RESTART; 147251881Speter sigaction (SIGURG, &act, NULL); 148251881Speter 149251881Speter /* Install a signal handler for SIGXCPU */ 150251881Speter sigemptyset (&act.sa_mask); 151251881Speter sigaddset (&act.sa_mask, SIGXCPU); 152251881Speter sigaction (SIGXCPU, &act, NULL); 153251881Speter 154251881Speter /* 155251881Speter * Initialize the thread attribute. 156251881Speter */ 157251881Speter if ((pthread_attr_init (&pattr) != 0) || 158251881Speter (pthread_attr_setdetachstate (&pattr, 159251881Speter PTHREAD_CREATE_JOINABLE) != 0)) { 160251881Speter fprintf (stderr, "Unable to initialize thread attributes.\n"); 161251881Speter exit (1); 162251881Speter } 163251881Speter 164251881Speter /* 165251881Speter * Initialize and create a mutex. 166251881Speter */ 167251881Speter if ((pthread_mutexattr_init (&mattr) != 0) || 168251881Speter (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) { 169251881Speter fprintf (stderr, "Unable to create waiter mutex.\n"); 170251881Speter exit (1); 171251881Speter } 172251881Speter 173251881Speter /* 174251881Speter * Create the sigwaiter thread. 175251881Speter */ 176251881Speter if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) { 177251881Speter fprintf (stderr, "Unable to create thread.\n"); 178251881Speter exit (1); 179251881Speter } 180251881Speter#if defined(_LIBC_R_) 181251881Speter pthread_set_name_np (tid, "sigwaiter"); 182251881Speter#endif 183251881Speter 184251881Speter /* 185251881Speter * Verify that an ignored signal doesn't cause a wakeup. 186251881Speter * We don't have a handler installed for SIGIO. 187251881Speter */ 188251881Speter send_thread_signal (tid, SIGIO); 189251881Speter sleep (1); 190251881Speter send_process_signal (SIGIO); 191251881Speter sleep (1); 192251881Speter if (sigcounts[SIGIO] != 0) 193251881Speter fprintf (stderr, 194251881Speter "FAIL: sigwait wakes up for ignored signal SIGIO.\n"); 195251881Speter 196251881Speter /* 197251881Speter * Verify that a signal with a default action of ignore, for 198251881Speter * which we have a signal handler installed, will release a sigwait. 199251881Speter */ 200251881Speter send_thread_signal (tid, SIGURG); 201251881Speter sleep (1); 202251881Speter send_process_signal (SIGURG); 203251881Speter sleep (1); 204251881Speter if (sigcounts[SIGURG] != 2) 205251881Speter fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n"); 206251881Speter 207251881Speter /* 208251881Speter * Verify that a signal with a default action that terminates 209251881Speter * the process will release a sigwait. 210251881Speter */ 211251881Speter send_thread_signal (tid, SIGUSR1); 212251881Speter sleep (1); 213251881Speter send_process_signal (SIGUSR1); 214251881Speter sleep (1); 215251881Speter if (sigcounts[SIGUSR1] != 2) 216251881Speter fprintf (stderr, 217251881Speter "FAIL: sigwait doesn't wake up for SIGUSR1.\n"); 218251881Speter 219251881Speter /* 220251881Speter * Verify that if we install a signal handler for a previously 221251881Speter * ignored signal, an occurrence of this signal will release 222251881Speter * the (already waiting) sigwait. 223251881Speter */ 224251881Speter 225251881Speter /* Install a signal handler for SIGHUP. */ 226251881Speter sigemptyset (&act.sa_mask); 227251881Speter sigaddset (&act.sa_mask, SIGHUP); 228251881Speter act.sa_handler = sighandler; 229251881Speter act.sa_flags = SA_RESTART; 230251881Speter sigaction (SIGHUP, &act, NULL); 231251881Speter 232251881Speter /* Sending SIGHUP should release the sigwait. */ 233251881Speter send_process_signal (SIGHUP); 234251881Speter sleep (1); 235251881Speter send_thread_signal (tid, SIGHUP); 236251881Speter sleep (1); 237251881Speter if (sigcounts[SIGHUP] != 2) 238251881Speter fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n"); 239251881Speter 240251881Speter /* 241251881Speter * Verify that a pending signal in the waiters mask will 242251881Speter * cause sigwait to return the pending signal. We do this 243251881Speter * by taking the waiters mutex and signaling the waiter to 244251881Speter * release him from the sigwait. The waiter will block 245251881Speter * on taking the mutex, and we can then send the waiter a 246251881Speter * signal which should be added to his pending signals. 247251881Speter * The next time the waiter does a sigwait, he should 248251881Speter * return with the pending signal. 249251881Speter */ 250251881Speter sigcounts[SIGHUP] = 0; 251251881Speter pthread_mutex_lock (&waiter_mutex); 252251881Speter /* Release the waiter from sigwait. */ 253251881Speter send_process_signal (SIGHUP); 254251881Speter sleep (1); 255251881Speter if (sigcounts[SIGHUP] != 1) 256251881Speter fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n"); 257251881Speter /* 258251881Speter * Add SIGHUP to the process pending signals. Since there is 259251881Speter * a signal handler installed for SIGHUP and this signal is 260251881Speter * blocked from the waiter thread and unblocked in the main 261251881Speter * thread, the signal handler should be called once for SIGHUP. 262251881Speter */ 263251881Speter send_process_signal (SIGHUP); 264251881Speter /* Release the waiter thread and allow him to run. */ 265251881Speter pthread_mutex_unlock (&waiter_mutex); 266251881Speter sleep (1); 267251881Speter if (sigcounts[SIGHUP] != 2) 268251881Speter fprintf (stderr, 269251881Speter "FAIL: sigwait doesn't return for pending SIGHUP.\n"); 270251881Speter 271251881Speter /* 272251881Speter * Repeat the above test using pthread_kill and SIGUSR1. 273251881Speter */ 274251881Speter sigcounts[SIGUSR1] = 0; 275251881Speter pthread_mutex_lock (&waiter_mutex); 276251881Speter /* Release the waiter from sigwait. */ 277251881Speter send_thread_signal (tid, SIGUSR1); 278251881Speter sleep (1); 279251881Speter if (sigcounts[SIGUSR1] != 1) 280251881Speter fprintf (stderr, 281251881Speter "FAIL: sigwait doesn't wake up for SIGUSR1.\n"); 282251881Speter /* Add SIGUSR1 to the waiters pending signals. */ 283251881Speter send_thread_signal (tid, SIGUSR1); 284251881Speter /* Release the waiter thread and allow him to run. */ 285251881Speter pthread_mutex_unlock (&waiter_mutex); 286251881Speter sleep (1); 287251881Speter if (sigcounts[SIGUSR1] != 2) 288251881Speter fprintf (stderr, 289251881Speter "FAIL: sigwait doesn't return for pending SIGUSR1.\n"); 290251881Speter 291251881Speter /* 292251881Speter * Verify that we can still kill the process for a signal 293251881Speter * not being waited on by sigwait. 294251881Speter */ 295251881Speter send_process_signal (SIGPIPE); 296251881Speter fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n"); 297251881Speter 298251881Speter /* 299251881Speter * Wait for the thread to finish. 300251881Speter */ 301251881Speter pthread_join (tid, &exit_status); 302251881Speter 303251881Speter return (0); 304251881Speter} 305251881Speter