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