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