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