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
SIG_init()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
SIG_handle(sig)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
SIG_register(sig,fn)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
SIG_deregister(sig,fn)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
SIG_beginCrSect()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
SIG_inCrSect()394 int SIG_inCrSect()
395 {
396 return SIG_crSectNest > 0;
397 }
398
399 /*
400 * The following ends a critical section.
401 */
402
SIG_endCrSect()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