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