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