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