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