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__ 53 char *calloc(unsigned nelem, unsigned size); 54 char *malloc(unsigned size); 55 #else 56 char *calloc(); 57 char *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 */ 67 struct 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 77 static struct SIG_hlist **SIG_handlers; 78 79 /* Define array of default signal vectors */ 80 81 #ifdef POSIX_SIGNALS 82 static struct sigaction *SIG_defaults; 83 #else 84 #ifdef BSD_SIGNALS 85 static struct sigvec *SIG_defaults; 86 #else 87 static RETSIGTYPE (**SIG_defaults) PROTO ((int)); 88 #endif 89 #endif 90 91 /* Critical section housekeeping */ 92 static int SIG_crSectNest = 0; /* Nesting level */ 93 #ifdef POSIX_SIGNALS 94 static sigset_t SIG_crSectMask; /* Signal mask */ 95 #else 96 static int SIG_crSectMask; /* Signal mask */ 97 #endif 98 99 /* 100 * Initialize the signal handler arrays 101 */ 102 103 static 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 */ 147 static RETSIGTYPE SIG_handle PROTO ((int)); 148 149 static RETSIGTYPE SIG_handle(sig) 150 int 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 173 int SIG_register(sig,fn) 174 int sig; 175 RETSIGTYPE (*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 memset(&act, 0, sizeof act); 226 act.sa_handler = SIG_handle; 227 (void) sigemptyset(&act.sa_mask); 228 act.sa_flags = 0; 229 val = sigaction(sig, &act, &SIG_defaults[sig]); 230 #else 231 #ifdef BSD_SIGNALS 232 memset (&vec, 0, sizeof (vec)); 233 vec.sv_handler = SIG_handle; 234 val = sigvec(sig, &vec, &SIG_defaults[sig]); 235 #else 236 if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == SIG_ERR) 237 val = -1; 238 #endif 239 #endif 240 } 241 242 /* If not, register it */ 243 if ((val == 0) && (this == (struct SIG_hlist *) NULL)) 244 { 245 this = (struct SIG_hlist *) 246 malloc(sizeof(struct SIG_hlist)); 247 if (this == NULL) 248 { 249 val = -1; 250 } 251 else 252 { 253 this->handler = fn; 254 this->next = SIG_handlers[sig]; 255 SIG_handlers[sig] = this; 256 } 257 } 258 } 259 260 /* Unblock the signal */ 261 #ifdef POSIX_SIGNALS 262 (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL); 263 #else 264 #ifdef BSD_SIGNALS 265 (void) sigsetmask(mask); 266 #endif 267 #endif 268 269 return val; 270 } 271 272 /* 273 * The following deregisters a signal handler. If the last signal handler for 274 * a given signal is deregistered, the default sigvec information is restored. 275 */ 276 277 int SIG_deregister(sig,fn) 278 int sig; 279 RETSIGTYPE (*fn)(); 280 { 281 int val; 282 struct SIG_hlist *this; 283 struct SIG_hlist *last; 284 #ifdef POSIX_SIGNALS 285 sigset_t sigset_mask, sigset_omask; 286 #else 287 #ifdef BSD_SIGNALS 288 int mask; 289 #endif 290 #endif 291 292 /* Initialize */ 293 if (SIG_init() != 0) 294 return (-1); 295 val = 0; 296 last = (struct SIG_hlist *) NULL; 297 298 /* Block this signal while we look at handler chain */ 299 #ifdef POSIX_SIGNALS 300 (void) sigemptyset(&sigset_mask); 301 (void) sigaddset(&sigset_mask, sig); 302 (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask); 303 #else 304 #ifdef BSD_SIGNALS 305 mask = sigblock(sigmask(sig)); 306 #endif 307 #endif 308 309 /* Search for the signal handler */ 310 this = SIG_handlers[sig]; 311 while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn)) 312 { 313 last = this; 314 this = this->next; 315 } 316 317 /* If it was registered, remove it */ 318 if (this != (struct SIG_hlist *) NULL) 319 { 320 if (last == (struct SIG_hlist *) NULL) 321 { 322 SIG_handlers[sig] = this->next; 323 } 324 else 325 { 326 last->next = this->next; 327 } 328 free((char *) this); 329 } 330 331 /* Restore default behavior if there are no registered handlers */ 332 if (SIG_handlers[sig] == (struct SIG_hlist *) NULL) 333 { 334 #ifdef POSIX_SIGNALS 335 val = sigaction(sig, &SIG_defaults[sig], 336 (struct sigaction *) NULL); 337 #else 338 #ifdef BSD_SIGNALS 339 val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL); 340 #else 341 if (signal(sig, SIG_defaults[sig]) == SIG_ERR) 342 val = -1; 343 #endif 344 #endif 345 } 346 347 /* Unblock the signal */ 348 #ifdef POSIX_SIGNALS 349 (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL); 350 #else 351 #ifdef BSD_SIGNALS 352 (void) sigsetmask(mask); 353 #endif 354 #endif 355 356 return val; 357 } 358 359 /* 360 * The following begins a critical section. 361 */ 362 363 void SIG_beginCrSect() 364 { 365 if (SIG_init() == 0) 366 { 367 if (SIG_crSectNest == 0) 368 { 369 #ifdef POSIX_SIGNALS 370 sigset_t sigset_mask; 371 372 (void) sigfillset(&sigset_mask); 373 (void) sigprocmask(SIG_SETMASK, 374 &sigset_mask, &SIG_crSectMask); 375 #else 376 #ifdef BSD_SIGNALS 377 SIG_crSectMask = sigblock(~0); 378 #else 379 /* TBD */ 380 #endif 381 #endif 382 } 383 SIG_crSectNest++; 384 } 385 } 386 387 /* 388 * Return nonzero if currently in a critical section. 389 * Otherwise return zero. 390 */ 391 392 int SIG_inCrSect() 393 { 394 return SIG_crSectNest > 0; 395 } 396 397 /* 398 * The following ends a critical section. 399 */ 400 401 void SIG_endCrSect() 402 { 403 if (SIG_init() == 0) 404 { 405 SIG_crSectNest--; 406 if (SIG_crSectNest == 0) 407 { 408 #ifdef POSIX_SIGNALS 409 (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL); 410 #else 411 #ifdef BSD_SIGNALS 412 (void) sigsetmask(SIG_crSectMask); 413 #else 414 /* TBD */ 415 #endif 416 #endif 417 } 418 } 419 } 420