]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/lib/sighandle.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / lib / sighandle.c
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 \f
99 /*
100  * Initialize the signal handler arrays
101  */
102
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 \f
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
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                 (*this->handler)(sig);
159                 this = this->next;
160         }
161
162         return;
163 }
164 \f
165 /*
166  * The following registers a signal handler.  If the handler is already
167  * registered, it is not registered twice, nor is the order in which signal
168  * handlers are invoked changed.  If this is the first signal handler
169  * registered for a given signal, the old sigvec structure is saved for
170  * restoration later.
171  */
172
173 int SIG_register(sig,fn)
174 int     sig;
175 RETSIGTYPE      (*fn)();
176 {
177         int                     val;
178         struct SIG_hlist        *this;
179 #ifdef POSIX_SIGNALS
180         struct sigaction        act;
181         sigset_t                sigset_mask, sigset_omask;
182 #else
183 #ifdef BSD_SIGNALS
184         struct sigvec           vec;
185         int                     mask;
186 #endif
187 #endif
188
189         /* Initialize */
190         if (SIG_init() != 0)
191                 return (-1);
192         val = 0;
193
194         /* Block this signal while we look at handler chain */
195 #ifdef POSIX_SIGNALS
196         (void) sigemptyset(&sigset_mask);
197         (void) sigaddset(&sigset_mask, sig);
198         (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
199 #else
200 #ifdef BSD_SIGNALS
201         mask = sigblock(sigmask(sig));
202 #endif
203 #endif
204
205         /* See if this handler was already registered */
206         this = SIG_handlers[sig];
207         while (this != (struct SIG_hlist *) NULL)
208         {
209                 if (this->handler == fn) break;
210                 this = this->next;
211         }
212
213         /* Register the new handler only if it is not already registered. */
214         if (this == (struct SIG_hlist *) NULL)
215         {
216
217                 /*
218                  * If this is the first handler registered for this signal,
219                  * set up the signal handler dispatcher
220                  */
221
222                 if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
223                 {
224 #ifdef POSIX_SIGNALS
225                         act.sa_handler = SIG_handle;
226                         (void) sigemptyset(&act.sa_mask);
227                         act.sa_flags = 0;
228                         val = sigaction(sig, &act, &SIG_defaults[sig]);
229 #else
230 #ifdef BSD_SIGNALS
231                         memset (&vec, 0, sizeof (vec));
232                         vec.sv_handler = SIG_handle;
233                         val = sigvec(sig, &vec, &SIG_defaults[sig]);
234 #else
235                         if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == SIG_ERR)
236                                 val = -1;
237 #endif
238 #endif
239                 }
240
241                 /* If not, register it */
242                 if ((val == 0) && (this == (struct SIG_hlist *) NULL))
243                 {
244                         this = (struct SIG_hlist *)
245                                               malloc(sizeof(struct SIG_hlist));
246                         if (this == NULL)
247                         {
248                                 val = -1;
249                         }
250                         else
251                         {
252                                 this->handler = fn;
253                                 this->next = SIG_handlers[sig];
254                                 SIG_handlers[sig] = this;
255                         }
256                 }
257         }
258
259         /* Unblock the signal */
260 #ifdef POSIX_SIGNALS
261         (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
262 #else
263 #ifdef BSD_SIGNALS
264         (void) sigsetmask(mask);
265 #endif
266 #endif
267
268         return val;
269 }
270 \f
271 /*
272  * The following deregisters a signal handler.  If the last signal handler for
273  * a given signal is deregistered, the default sigvec information is restored.
274  */
275
276 int SIG_deregister(sig,fn)
277 int     sig;
278 RETSIGTYPE      (*fn)();
279 {
280         int                     val;
281         struct SIG_hlist        *this;
282         struct SIG_hlist        *last;
283 #ifdef POSIX_SIGNALS
284         sigset_t                sigset_mask, sigset_omask;
285 #else
286 #ifdef BSD_SIGNALS
287         int                     mask;
288 #endif
289 #endif
290
291         /* Initialize */
292         if (SIG_init() != 0)
293                 return (-1);
294         val = 0;
295         last = (struct SIG_hlist *) NULL;
296
297         /* Block this signal while we look at handler chain */
298 #ifdef POSIX_SIGNALS
299         (void) sigemptyset(&sigset_mask);
300         (void) sigaddset(&sigset_mask, sig);
301         (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
302 #else
303 #ifdef BSD_SIGNALS
304         mask = sigblock(sigmask(sig));
305 #endif
306 #endif
307
308         /* Search for the signal handler */
309         this = SIG_handlers[sig];
310         while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn))
311         {
312                 last = this;
313                 this = this->next;
314         }
315
316         /* If it was registered, remove it */
317         if (this != (struct SIG_hlist *) NULL)
318         {
319                 if (last == (struct SIG_hlist *) NULL)
320                 {
321                         SIG_handlers[sig] = this->next;
322                 }
323                 else
324                 {
325                         last->next = this->next;
326                 }
327                 free((char *) this);
328         }
329
330         /* Restore default behavior if there are no registered handlers */
331         if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
332         {
333 #ifdef POSIX_SIGNALS
334                 val = sigaction(sig, &SIG_defaults[sig],
335                                 (struct sigaction *) NULL);
336 #else
337 #ifdef BSD_SIGNALS
338                 val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL);
339 #else
340                 if (signal(sig, SIG_defaults[sig]) == SIG_ERR)
341                         val = -1;
342 #endif
343 #endif
344         }
345
346         /* Unblock the signal */
347 #ifdef POSIX_SIGNALS
348         (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
349 #else
350 #ifdef BSD_SIGNALS
351         (void) sigsetmask(mask);
352 #endif
353 #endif
354
355         return val;
356 }
357 \f
358 /*
359  * The following begins a critical section.
360  */
361
362 void SIG_beginCrSect()
363 {
364         if (SIG_init() == 0)
365         {
366                 if (SIG_crSectNest == 0)
367                 {
368 #ifdef POSIX_SIGNALS
369                         sigset_t sigset_mask;
370
371                         (void) sigfillset(&sigset_mask);
372                         (void) sigprocmask(SIG_SETMASK,
373                                            &sigset_mask, &SIG_crSectMask);
374 #else
375 #ifdef BSD_SIGNALS
376                         SIG_crSectMask = sigblock(~0);
377 #else
378                         /* TBD */
379 #endif
380 #endif
381                 }
382                 SIG_crSectNest++;
383         }
384 }
385 \f
386 /*
387  * Return nonzero if currently in a critical section.
388  * Otherwise return zero.
389  */
390
391 int SIG_inCrSect()
392 {
393         return SIG_crSectNest > 0;
394 }
395 \f
396 /*
397  * The following ends a critical section.
398  */
399
400 void SIG_endCrSect()
401 {
402         if (SIG_init() == 0)
403         {
404                 SIG_crSectNest--;
405                 if (SIG_crSectNest == 0)
406                 {
407 #ifdef POSIX_SIGNALS
408                         (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL);
409 #else
410 #ifdef BSD_SIGNALS
411                         (void) sigsetmask(SIG_crSectMask);
412 #else
413                         /* TBD */
414 #endif
415 #endif
416                 }
417         }
418 }