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