xref: /netbsd-src/external/gpl2/xcvs/dist/lib/sighandle.c (revision 5a6c14c844c4c665da5632061aebde7bb2cb5766)
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 #include <sys/cdefs.h>
14 __RCSID("$NetBSD: sighandle.c,v 1.2 2016/05/17 14:00:09 christos Exp $");
15 
16 /* Written by Paul Sander, HaL Computer Systems, Inc. <paul@hal.com>
17    Brian Berliner <berliner@Sun.COM> added POSIX support */
18 
19 /*************************************************************************
20  *
21  * signal.c -- This file contains code that manipulates chains of signal
22  *             handlers.
23  *
24  *             Facilities are provided to register a signal handler for
25  *             any specific signal.  When a signal is received, all of the
26  *             registered signal handlers are invoked in the reverse order
27  *             in which they are registered.  Note that the signal handlers
28  *             must not themselves make calls to the signal handling
29  *             facilities.
30  *
31  *************************************************************************/
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 #include "system.h"
37 
38 #include <sys/types.h>
39 #include <stdio.h>
40 #include <signal.h>
41 
42 #ifdef STDC_HEADERS
43 #include <stdlib.h>
44 #else
45 #if __STDC__
46 char *calloc(unsigned nelem, unsigned size);
47 char *malloc(unsigned size);
48 #else
49 char *calloc();
50 char *malloc();
51 #endif /* __STDC__ */
52 #endif /* STDC_HEADERS */
53 
54 /* Define the highest signal number (usually) */
55 #ifndef SIGMAX
56 #define	SIGMAX	64
57 #endif
58 
59 /* Define linked list of signal handlers structure */
60 struct SIG_hlist {
61 	RETSIGTYPE		(*handler)();
62 	struct SIG_hlist	*next;
63 };
64 
65 /*
66  * Define array of lists of signal handlers.  Note that this depends on
67  * the implementation to initialize each element to a null pointer.
68  */
69 
70 static	struct SIG_hlist	**SIG_handlers;
71 
72 /* Define array of default signal vectors */
73 
74 #ifdef POSIX_SIGNALS
75 static	struct sigaction	*SIG_defaults;
76 #else
77 #ifdef BSD_SIGNALS
78 static	struct sigvec		*SIG_defaults;
79 #else
80 static	RETSIGTYPE		(**SIG_defaults) (int);
81 #endif
82 #endif
83 
84 /* Critical section housekeeping */
85 static	int		SIG_crSectNest = 0;	/* Nesting level */
86 #ifdef POSIX_SIGNALS
87 static	sigset_t	SIG_crSectMask;		/* Signal mask */
88 #else
89 static	int		SIG_crSectMask;		/* Signal mask */
90 #endif
91 
92 /*
93  * Initialize the signal handler arrays
94  */
95 
SIG_init()96 static int SIG_init()
97 {
98 	int i;
99 #ifdef POSIX_SIGNALS
100 	sigset_t sigset_test;
101 #endif
102 
103 	if (SIG_defaults && SIG_handlers)	/* already allocated */
104 		return (0);
105 
106 #ifdef POSIX_SIGNALS
107 	(void) sigfillset(&sigset_test);
108 	for (i = 1; i < SIGMAX && sigismember(&sigset_test, i) == 1; i++)
109 		;
110 	if (i < SIGMAX)
111 		i = SIGMAX;
112 	i++;
113 	if (!SIG_defaults)
114 		SIG_defaults = (struct sigaction *)
115 			calloc(i, sizeof(struct sigaction));
116 	(void) sigemptyset(&SIG_crSectMask);
117 #else
118 	i = SIGMAX+1;
119 #ifdef BSD_SIGNALS
120 	if (!SIG_defaults)
121 		SIG_defaults = (struct sigvec *)
122 			calloc(i, sizeof(struct sigvec));
123 #else
124 	if (!SIG_defaults)
125 		SIG_defaults = ( RETSIGTYPE (**) (int) )
126 			calloc( i, sizeof( RETSIGTYPE (**) (int) ) );
127 #endif
128 	SIG_crSectMask = 0;
129 #endif
130 	if (!SIG_handlers)
131 		SIG_handlers = (struct SIG_hlist **)
132 			calloc(i, sizeof(struct SIG_hlist *));
133 	return (!SIG_defaults || !SIG_handlers);
134 }
135 
136 
137 
138 /*
139  * The following begins a critical section.
140  */
SIG_beginCrSect(void)141 void SIG_beginCrSect (void)
142 {
143 	if (SIG_init() == 0)
144 	{
145 		if (SIG_crSectNest == 0)
146 		{
147 #ifdef POSIX_SIGNALS
148 			sigset_t sigset_mask;
149 
150 			(void) sigfillset(&sigset_mask);
151 			(void) sigprocmask(SIG_SETMASK,
152 					   &sigset_mask, &SIG_crSectMask);
153 #else
154 #ifdef BSD_SIGNALS
155 			SIG_crSectMask = sigblock(~0);
156 #else
157 			/* TBD */
158 #endif
159 #endif
160 		}
161 		SIG_crSectNest++;
162 	}
163 }
164 
165 
166 
167 /*
168  * The following ends a critical section.
169  */
SIG_endCrSect(void)170 void SIG_endCrSect (void)
171 {
172 	if (SIG_init() == 0)
173 	{
174 		SIG_crSectNest--;
175 		if (SIG_crSectNest == 0)
176 		{
177 #ifdef POSIX_SIGNALS
178 			(void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL);
179 #else
180 #ifdef BSD_SIGNALS
181 			(void) sigsetmask(SIG_crSectMask);
182 #else
183 			/* TBD */
184 #endif
185 #endif
186 		}
187 	}
188 }
189 
190 
191 
192 /*
193  * The following invokes each signal handler in the reverse order in which
194  * they were registered.
195  */
SIG_handle(int sig)196 static RETSIGTYPE SIG_handle (int sig)
197 {
198 	struct SIG_hlist	*this;
199 
200 	/* Dispatch signal handlers */
201 	/* This crit section stuff is a CVSism - we know that our interrupt
202 	 * handlers will always end up exiting and we don't want them to be
203 	 * interrupted themselves.
204 	 */
205 	SIG_beginCrSect();
206 	this = SIG_handlers[sig];
207 	while (this != (struct SIG_hlist *) NULL)
208 	{
209 		(*this->handler)(sig);
210 		this = this->next;
211 	}
212 	SIG_endCrSect();
213 
214 	return;
215 }
216 
217 /*
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 
SIG_register(int sig,RETSIGTYPE (* fn)())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 
SIG_deregister(int sig,RETSIGTYPE (* fn)())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 
SIG_inCrSect(void)415 int SIG_inCrSect (void)
416 {
417 	return SIG_crSectNest > 0;
418 }
419