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