1/* sighandle.c -- Library routines for manipulating chains of signal handlers 2 Copyright (C) 1992 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. */ 13 14/* Written by Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> 15 Brian Berliner <berliner@Sun.COM> added POSIX support */ 16 17/************************************************************************* 18 * 19 * signal.c -- This file contains code that manipulates chains of signal 20 * handlers. 21 * 22 * Facilities are provided to register a signal handler for 23 * any specific signal. When a signal is received, all of the 24 * registered signal handlers are invoked in the reverse order 25 * in which they are registered. Note that the signal handlers 26 * must not themselves make calls to the signal handling 27 * facilities. 28 * 29 *************************************************************************/ 30 31#ifdef HAVE_CONFIG_H 32#include "config.h" 33#endif 34#include "system.h" 35 36#include <sys/types.h> 37#include <stdio.h> 38#include <signal.h> 39 40/* Add prototype support. */ 41#ifndef PROTO 42#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) 43#define PROTO(ARGS) ARGS 44#else 45#define PROTO(ARGS) () 46#endif 47#endif 48 49#ifdef STDC_HEADERS 50#include <stdlib.h> 51#else 52#if __STDC__ 53char *calloc(unsigned nelem, unsigned size); 54char *malloc(unsigned size); 55#else 56char *calloc(); 57char *malloc(); 58#endif /* __STDC__ */ 59#endif /* STDC_HEADERS */ 60 61/* Define the highest signal number (usually) */ 62#ifndef SIGMAX 63#define SIGMAX 64 64#endif 65 66/* Define linked list of signal handlers structure */ 67struct SIG_hlist { 68 RETSIGTYPE (*handler)(); 69 struct SIG_hlist *next; 70}; 71 72/* 73 * Define array of lists of signal handlers. Note that this depends on 74 * the implementation to initialize each element to a null pointer. 75 */ 76 77static struct SIG_hlist **SIG_handlers; 78 79/* Define array of default signal vectors */ 80 81#ifdef POSIX_SIGNALS 82static struct sigaction *SIG_defaults; 83#else 84#ifdef BSD_SIGNALS 85static struct sigvec *SIG_defaults; 86#else 87static RETSIGTYPE (**SIG_defaults) PROTO ((int)); 88#endif 89#endif 90 91/* Critical section housekeeping */ 92static int SIG_crSectNest = 0; /* Nesting level */ 93#ifdef POSIX_SIGNALS 94static sigset_t SIG_crSectMask; /* Signal mask */ 95#else 96static int SIG_crSectMask; /* Signal mask */ 97#endif 98 99/* 100 * Initialize the signal handler arrays 101 */ 102 103static int SIG_init() 104{ 105 int i; 106#ifdef POSIX_SIGNALS 107 sigset_t sigset_test; 108#endif 109 110 if (SIG_defaults && SIG_handlers) /* already allocated */ 111 return (0); 112 113#ifdef POSIX_SIGNALS 114 (void) sigfillset(&sigset_test); 115 for (i = 1; i < SIGMAX && sigismember(&sigset_test, i) == 1; i++) 116 ; 117 if (i < SIGMAX) 118 i = SIGMAX; 119 i++; 120 if (!SIG_defaults) 121 SIG_defaults = (struct sigaction *) 122 calloc(i, sizeof(struct sigaction)); 123 (void) sigemptyset(&SIG_crSectMask); 124#else 125 i = SIGMAX+1; 126#ifdef BSD_SIGNALS 127 if (!SIG_defaults) 128 SIG_defaults = (struct sigvec *) 129 calloc(i, sizeof(struct sigvec)); 130#else 131 if (!SIG_defaults) 132 SIG_defaults = (RETSIGTYPE (**) PROTO ((int)) ) 133 calloc(i, sizeof(RETSIGTYPE (**) PROTO ((int)) )); 134#endif 135 SIG_crSectMask = 0; 136#endif 137 if (!SIG_handlers) 138 SIG_handlers = (struct SIG_hlist **) 139 calloc(i, sizeof(struct SIG_hlist *)); 140 return (!SIG_defaults || !SIG_handlers); 141} 142 143/* 144 * The following invokes each signal handler in the reverse order in which 145 * they were registered. 146 */ 147static RETSIGTYPE SIG_handle PROTO ((int)); 148 149static RETSIGTYPE SIG_handle(sig) 150int sig; 151{ 152 struct SIG_hlist *this; 153 154 /* Dispatch signal handlers */ 155 this = SIG_handlers[sig]; 156 while (this != (struct SIG_hlist *) NULL) 157 { 158 (*this->handler)(sig); 159 this = this->next; 160 } 161 162 return; 163} 164 165/* 166 * The following registers a signal handler. If the handler is already 167 * registered, it is not registered twice, nor is the order in which signal 168 * handlers are invoked changed. If this is the first signal handler 169 * registered for a given signal, the old sigvec structure is saved for 170 * restoration later. 171 */ 172 173int SIG_register(sig,fn) 174int sig; 175RETSIGTYPE (*fn)(); 176{ 177 int val; 178 struct SIG_hlist *this; 179#ifdef POSIX_SIGNALS 180 struct sigaction act; 181 sigset_t sigset_mask, sigset_omask; 182#else 183#ifdef BSD_SIGNALS 184 struct sigvec vec; 185 int mask; 186#endif 187#endif 188 189 /* Initialize */ 190 if (SIG_init() != 0) 191 return (-1); 192 val = 0; 193 194 /* Block this signal while we look at handler chain */ 195#ifdef POSIX_SIGNALS 196 (void) sigemptyset(&sigset_mask); 197 (void) sigaddset(&sigset_mask, sig); 198 (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask); 199#else 200#ifdef BSD_SIGNALS 201 mask = sigblock(sigmask(sig)); 202#endif 203#endif 204 205 /* See if this handler was already registered */ 206 this = SIG_handlers[sig]; 207 while (this != (struct SIG_hlist *) NULL) 208 { 209 if (this->handler == fn) break; 210 this = this->next; 211 } 212 213 /* Register the new handler only if it is not already registered. */ 214 if (this == (struct SIG_hlist *) NULL) 215 { 216 217 /* 218 * If this is the first handler registered for this signal, 219 * set up the signal handler dispatcher 220 */ 221 222 if (SIG_handlers[sig] == (struct SIG_hlist *) NULL) 223 { 224#ifdef POSIX_SIGNALS 225 act.sa_handler = SIG_handle; 226 (void) sigemptyset(&act.sa_mask); 227 act.sa_flags = 0; 228 val = sigaction(sig, &act, &SIG_defaults[sig]); 229#else 230#ifdef BSD_SIGNALS 231 memset (&vec, 0, sizeof (vec)); 232 vec.sv_handler = SIG_handle; 233 val = sigvec(sig, &vec, &SIG_defaults[sig]); 234#else 235 if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == SIG_ERR) 236 val = -1; 237#endif 238#endif 239 } 240 241 /* If not, register it */ 242 if ((val == 0) && (this == (struct SIG_hlist *) NULL)) 243 { 244 this = (struct SIG_hlist *) 245 malloc(sizeof(struct SIG_hlist)); 246 if (this == NULL) 247 { 248 val = -1; 249 } 250 else 251 { 252 this->handler = fn; 253 this->next = SIG_handlers[sig]; 254 SIG_handlers[sig] = this; 255 } 256 } 257 } 258 259 /* Unblock the signal */ 260#ifdef POSIX_SIGNALS 261 (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL); 262#else 263#ifdef BSD_SIGNALS 264 (void) sigsetmask(mask); 265#endif 266#endif 267 268 return val; 269} 270 271/* 272 * The following deregisters a signal handler. If the last signal handler for 273 * a given signal is deregistered, the default sigvec information is restored. 274 */ 275 276int SIG_deregister(sig,fn) 277int sig; 278RETSIGTYPE (*fn)(); 279{ 280 int val; 281 struct SIG_hlist *this; 282 struct SIG_hlist *last; 283#ifdef POSIX_SIGNALS 284 sigset_t sigset_mask, sigset_omask; 285#else 286#ifdef BSD_SIGNALS 287 int mask; 288#endif 289#endif 290 291 /* Initialize */ 292 if (SIG_init() != 0) 293 return (-1); 294 val = 0; 295 last = (struct SIG_hlist *) NULL; 296 297 /* Block this signal while we look at handler chain */ 298#ifdef POSIX_SIGNALS 299 (void) sigemptyset(&sigset_mask); 300 (void) sigaddset(&sigset_mask, sig); 301 (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask); 302#else 303#ifdef BSD_SIGNALS 304 mask = sigblock(sigmask(sig)); 305#endif 306#endif 307 308 /* Search for the signal handler */ 309 this = SIG_handlers[sig]; 310 while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn)) 311 { 312 last = this; 313 this = this->next; 314 } 315 316 /* If it was registered, remove it */ 317 if (this != (struct SIG_hlist *) NULL) 318 { 319 if (last == (struct SIG_hlist *) NULL) 320 { 321 SIG_handlers[sig] = this->next; 322 } 323 else 324 { 325 last->next = this->next; 326 } 327 free((char *) this); 328 } 329 330 /* Restore default behavior if there are no registered handlers */ 331 if (SIG_handlers[sig] == (struct SIG_hlist *) NULL) 332 { 333#ifdef POSIX_SIGNALS 334 val = sigaction(sig, &SIG_defaults[sig], 335 (struct sigaction *) NULL); 336#else 337#ifdef BSD_SIGNALS 338 val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL); 339#else 340 if (signal(sig, SIG_defaults[sig]) == SIG_ERR) 341 val = -1; 342#endif 343#endif 344 } 345 346 /* Unblock the signal */ 347#ifdef POSIX_SIGNALS 348 (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL); 349#else 350#ifdef BSD_SIGNALS 351 (void) sigsetmask(mask); 352#endif 353#endif 354 355 return val; 356} 357 358/* 359 * The following begins a critical section. 360 */ 361 362void SIG_beginCrSect() 363{ 364 if (SIG_init() == 0) 365 { 366 if (SIG_crSectNest == 0) 367 { 368#ifdef POSIX_SIGNALS 369 sigset_t sigset_mask; 370 371 (void) sigfillset(&sigset_mask); 372 (void) sigprocmask(SIG_SETMASK, 373 &sigset_mask, &SIG_crSectMask); 374#else 375#ifdef BSD_SIGNALS 376 SIG_crSectMask = sigblock(~0); 377#else 378 /* TBD */ 379#endif 380#endif 381 } 382 SIG_crSectNest++; 383 } 384} 385 386/* 387 * Return nonzero if currently in a critical section. 388 * Otherwise return zero. 389 */ 390 391int SIG_inCrSect() 392{ 393 return SIG_crSectNest > 0; 394} 395 396/* 397 * The following ends a critical section. 398 */ 399 400void SIG_endCrSect() 401{ 402 if (SIG_init() == 0) 403 { 404 SIG_crSectNest--; 405 if (SIG_crSectNest == 0) 406 { 407#ifdef POSIX_SIGNALS 408 (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL); 409#else 410#ifdef BSD_SIGNALS 411 (void) sigsetmask(SIG_crSectMask); 412#else 413 /* TBD */ 414#endif 415#endif 416 } 417 } 418} 419