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