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