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