xref: /openbsd/gnu/usr.bin/cvs/lib/sighandle.c (revision 274d7c50)
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__
53 char *calloc(unsigned nelem, unsigned size);
54 char *malloc(unsigned size);
55 #else
56 char *calloc();
57 char *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 */
67 struct 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 
77 static	struct SIG_hlist	**SIG_handlers;
78 
79 /* Define array of default signal vectors */
80 
81 #ifdef POSIX_SIGNALS
82 static	struct sigaction	*SIG_defaults;
83 #else
84 #ifdef BSD_SIGNALS
85 static	struct sigvec		*SIG_defaults;
86 #else
87 static	RETSIGTYPE		(**SIG_defaults) PROTO ((int));
88 #endif
89 #endif
90 
91 /* Critical section housekeeping */
92 static	int		SIG_crSectNest = 0;	/* Nesting level */
93 #ifdef POSIX_SIGNALS
94 static	sigset_t	SIG_crSectMask;		/* Signal mask */
95 #else
96 static	int		SIG_crSectMask;		/* Signal mask */
97 #endif
98 
99 /*
100  * Initialize the signal handler arrays
101  */
102 
103 static 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  */
147 static RETSIGTYPE SIG_handle PROTO ((int));
148 
149 static RETSIGTYPE SIG_handle(sig)
150 int			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 		/* handler may free this (and thus clobber this->next) */
159 		struct SIG_hlist *current = this;
160 		this = this->next;
161 		(*current->handler)(sig);
162 	}
163 
164 	return;
165 }
166 
167 /*
168  * The following registers a signal handler.  If the handler is already
169  * registered, it is not registered twice, nor is the order in which signal
170  * handlers are invoked changed.  If this is the first signal handler
171  * registered for a given signal, the old sigvec structure is saved for
172  * restoration later.
173  */
174 
175 int SIG_register(sig,fn)
176 int	sig;
177 RETSIGTYPE	(*fn)();
178 {
179 	int			val;
180 	struct SIG_hlist	*this;
181 #ifdef POSIX_SIGNALS
182 	struct sigaction	act;
183 	sigset_t		sigset_mask, sigset_omask;
184 #else
185 #ifdef BSD_SIGNALS
186 	struct sigvec		vec;
187 	int			mask;
188 #endif
189 #endif
190 
191 	/* Initialize */
192 	if (SIG_init() != 0)
193 		return (-1);
194 	val = 0;
195 
196 	/* Block this signal while we look at handler chain */
197 #ifdef POSIX_SIGNALS
198 	(void) sigemptyset(&sigset_mask);
199 	(void) sigaddset(&sigset_mask, sig);
200 	(void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
201 #else
202 #ifdef BSD_SIGNALS
203 	mask = sigblock(sigmask(sig));
204 #endif
205 #endif
206 
207 	/* See if this handler was already registered */
208 	this = SIG_handlers[sig];
209 	while (this != (struct SIG_hlist *) NULL)
210 	{
211 		if (this->handler == fn) break;
212 		this = this->next;
213 	}
214 
215 	/* Register the new handler only if it is not already registered. */
216 	if (this == (struct SIG_hlist *) NULL)
217 	{
218 
219 		/*
220 		 * If this is the first handler registered for this signal,
221 		 * set up the signal handler dispatcher
222 		 */
223 
224 		if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
225 		{
226 #ifdef POSIX_SIGNALS
227 			memset(&act, 0, sizeof act);
228 			act.sa_handler = SIG_handle;
229 			(void) sigemptyset(&act.sa_mask);
230 			act.sa_flags = 0;
231 			val = sigaction(sig, &act, &SIG_defaults[sig]);
232 #else
233 #ifdef BSD_SIGNALS
234 			memset (&vec, 0, sizeof (vec));
235 			vec.sv_handler = SIG_handle;
236 			val = sigvec(sig, &vec, &SIG_defaults[sig]);
237 #else
238 			if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == SIG_ERR)
239 				val = -1;
240 #endif
241 #endif
242 		}
243 
244 		/* If not, register it */
245 		if ((val == 0) && (this == (struct SIG_hlist *) NULL))
246 		{
247 			this = (struct SIG_hlist *)
248 			                      malloc(sizeof(struct SIG_hlist));
249 			if (this == NULL)
250 			{
251 				val = -1;
252 			}
253 			else
254 			{
255 				this->handler = fn;
256 				this->next = SIG_handlers[sig];
257 				SIG_handlers[sig] = this;
258 			}
259 		}
260 	}
261 
262 	/* Unblock the signal */
263 #ifdef POSIX_SIGNALS
264 	(void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
265 #else
266 #ifdef BSD_SIGNALS
267 	(void) sigsetmask(mask);
268 #endif
269 #endif
270 
271 	return val;
272 }
273 
274 /*
275  * The following deregisters a signal handler.  If the last signal handler for
276  * a given signal is deregistered, the default sigvec information is restored.
277  */
278 
279 int SIG_deregister(sig,fn)
280 int	sig;
281 RETSIGTYPE	(*fn)();
282 {
283 	int			val;
284 	struct SIG_hlist	*this;
285 	struct SIG_hlist	*last;
286 #ifdef POSIX_SIGNALS
287 	sigset_t		sigset_mask, sigset_omask;
288 #else
289 #ifdef BSD_SIGNALS
290 	int			mask;
291 #endif
292 #endif
293 
294 	/* Initialize */
295 	if (SIG_init() != 0)
296 		return (-1);
297 	val = 0;
298 	last = (struct SIG_hlist *) NULL;
299 
300 	/* Block this signal while we look at handler chain */
301 #ifdef POSIX_SIGNALS
302 	(void) sigemptyset(&sigset_mask);
303 	(void) sigaddset(&sigset_mask, sig);
304 	(void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
305 #else
306 #ifdef BSD_SIGNALS
307 	mask = sigblock(sigmask(sig));
308 #endif
309 #endif
310 
311 	/* Search for the signal handler */
312 	this = SIG_handlers[sig];
313 	while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn))
314 	{
315 		last = this;
316 		this = this->next;
317 	}
318 
319 	/* If it was registered, remove it */
320 	if (this != (struct SIG_hlist *) NULL)
321 	{
322 		if (last == (struct SIG_hlist *) NULL)
323 		{
324 			SIG_handlers[sig] = this->next;
325 		}
326 		else
327 		{
328 			last->next = this->next;
329 		}
330 		free((char *) this);
331 	}
332 
333 	/* Restore default behavior if there are no registered handlers */
334 	if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
335 	{
336 #ifdef POSIX_SIGNALS
337 		val = sigaction(sig, &SIG_defaults[sig],
338 				(struct sigaction *) NULL);
339 #else
340 #ifdef BSD_SIGNALS
341 		val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL);
342 #else
343 		if (signal(sig, SIG_defaults[sig]) == SIG_ERR)
344 			val = -1;
345 #endif
346 #endif
347 	}
348 
349 	/* Unblock the signal */
350 #ifdef POSIX_SIGNALS
351 	(void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
352 #else
353 #ifdef BSD_SIGNALS
354 	(void) sigsetmask(mask);
355 #endif
356 #endif
357 
358 	return val;
359 }
360 
361 /*
362  * The following begins a critical section.
363  */
364 
365 void SIG_beginCrSect()
366 {
367 	if (SIG_init() == 0)
368 	{
369 		if (SIG_crSectNest == 0)
370 		{
371 #ifdef POSIX_SIGNALS
372 			sigset_t sigset_mask;
373 
374 			(void) sigfillset(&sigset_mask);
375 			(void) sigprocmask(SIG_SETMASK,
376 					   &sigset_mask, &SIG_crSectMask);
377 #else
378 #ifdef BSD_SIGNALS
379 			SIG_crSectMask = sigblock(~0);
380 #else
381 			/* TBD */
382 #endif
383 #endif
384 		}
385 		SIG_crSectNest++;
386 	}
387 }
388 
389 /*
390  * Return nonzero if currently in a critical section.
391  * Otherwise return zero.
392  */
393 
394 int SIG_inCrSect()
395 {
396 	return SIG_crSectNest > 0;
397 }
398 
399 /*
400  * The following ends a critical section.
401  */
402 
403 void SIG_endCrSect()
404 {
405 	if (SIG_init() == 0)
406 	{
407 		SIG_crSectNest--;
408 		if (SIG_crSectNest == 0)
409 		{
410 #ifdef POSIX_SIGNALS
411 			(void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL);
412 #else
413 #ifdef BSD_SIGNALS
414 			(void) sigsetmask(SIG_crSectMask);
415 #else
416 			/* TBD */
417 #endif
418 #endif
419 		}
420 	}
421 }
422