Mercurial > gnulib
annotate lib/fatal-signal.c @ 4786:83d8d561903a
Improved 'fatal-signal' module.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Tue, 14 Oct 2003 12:09:12 +0000 |
parents | 6708dc21dacc |
children | f64f1da7e350 |
rev | line source |
---|---|
4770 | 1 /* Emergency actions in case of a fatal signal. |
2 Copyright (C) 2003 Free Software Foundation, Inc. | |
3 Written by Bruno Haible <bruno@clisp.org>, 2003. | |
4 | |
5 This program is free software; you can redistribute it and/or modify | |
6 it under the terms of the GNU General Public License as published by | |
7 the Free Software Foundation; either version 2, or (at your option) | |
8 any later version. | |
9 | |
10 This program is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 GNU General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU General Public License | |
16 along with this program; if not, write to the Free Software Foundation, | |
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
18 | |
19 | |
20 #ifdef HAVE_CONFIG_H | |
21 # include "config.h" | |
22 #endif | |
23 | |
24 /* Specification. */ | |
25 #include "fatal-signal.h" | |
26 | |
27 #include <stdbool.h> | |
28 #include <stdlib.h> | |
29 #include <signal.h> | |
30 #include <string.h> | |
31 #if HAVE_UNISTD_H | |
32 # include <unistd.h> | |
33 #endif | |
34 | |
35 #include "xalloc.h" | |
36 | |
37 #define SIZEOF(a) (sizeof(a) / sizeof(a[0])) | |
38 | |
39 | |
40 /* ========================================================================= */ | |
41 | |
42 | |
43 /* The list of fatal signals. | |
44 These are those signals whose default action is to terminate the process | |
45 without a core dump, except | |
46 SIGKILL - because it cannot be caught, | |
47 SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications | |
48 often use them for their own purpose, | |
49 SIGPROF SIGVTALRM - because they are used for profiling, | |
50 SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS, | |
51 SIGSYS - because it is more similar to SIGABRT, SIGSEGV, | |
52 SIGPWR - because it of too special use, | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
53 SIGRTMIN...SIGRTMAX - because they are reserved for application use. |
4770 | 54 plus |
55 SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */ | |
56 | |
57 static const int fatal_signals[] = | |
58 { | |
59 /* ISO C 99 signals. */ | |
60 #ifdef SIGINT | |
61 SIGINT, | |
62 #endif | |
63 #ifdef SIGTERM | |
64 SIGTERM, | |
65 #endif | |
66 /* POSIX:2001 signals. */ | |
67 #ifdef SIGHUP | |
68 SIGHUP, | |
69 #endif | |
70 #ifdef SIGPIPE | |
71 SIGPIPE, | |
72 #endif | |
73 /* BSD signals. */ | |
74 #ifdef SIGXCPU | |
75 SIGXCPU, | |
76 #endif | |
77 #ifdef SIGXFSZ | |
78 SIGXFSZ, | |
79 #endif | |
80 0 | |
81 }; | |
82 | |
83 #define num_fatal_signals (SIZEOF (fatal_signals) - 1) | |
84 | |
85 | |
86 /* ========================================================================= */ | |
87 | |
88 | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
89 typedef void (*action_t) (void); |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
90 |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
91 /* Type of an entry in the actions array. |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
92 The 'action' field is accessed from within the fatal_signal_handler(), |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
93 therefore we mark it as 'volatile'. */ |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
94 typedef struct |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
95 { |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
96 volatile action_t action; |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
97 } |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
98 actions_entry_t; |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
99 |
4770 | 100 /* The registered cleanup actions. */ |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
101 static actions_entry_t static_actions[32]; |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
102 static actions_entry_t * volatile actions = static_actions; |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
103 static sig_atomic_t volatile actions_count = 0; |
4770 | 104 static size_t actions_allocated = SIZEOF (static_actions); |
105 | |
106 | |
107 /* Uninstall the handlers. */ | |
108 static inline void | |
109 uninstall_handlers () | |
110 { | |
111 size_t i; | |
112 | |
113 for (i = 0; i < num_fatal_signals; i++) | |
114 signal (fatal_signals[i], SIG_DFL); | |
115 } | |
116 | |
117 | |
118 /* The signal handler. It gets called asynchronously. */ | |
119 static void | |
120 fatal_signal_handler (int sig) | |
121 { | |
122 for (;;) | |
123 { | |
124 /* Get the last registered cleanup action, in a reentrant way. */ | |
125 action_t action; | |
126 size_t n = actions_count; | |
127 if (n == 0) | |
128 break; | |
129 n--; | |
130 actions_count = n; | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
131 action = actions[n].action; |
4770 | 132 /* Execute the action. */ |
133 action (); | |
134 } | |
135 | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
136 /* Now execute the signal's default action. |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
137 If signal() blocks the signal being delivered for the duration of the |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
138 signal handler's execution, the re-raised signal is delivered when this |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
139 handler returns; otherwise it is delivered already during raise(). */ |
4770 | 140 uninstall_handlers (); |
141 #if HAVE_RAISE | |
142 raise (sig); | |
143 #else | |
144 kill (getpid (), sig); | |
145 #endif | |
146 } | |
147 | |
148 | |
149 /* Install the handlers. */ | |
150 static inline void | |
151 install_handlers () | |
152 { | |
153 size_t i; | |
154 | |
155 for (i = 0; i < num_fatal_signals; i++) | |
156 signal (fatal_signals[i], &fatal_signal_handler); | |
157 } | |
158 | |
159 | |
160 /* Register a cleanup function to be executed when a catchable fatal signal | |
161 occurs. */ | |
162 void | |
163 at_fatal_signal (action_t action) | |
164 { | |
165 static bool cleanup_initialized = false; | |
166 if (!cleanup_initialized) | |
167 { | |
168 install_handlers (); | |
169 cleanup_initialized = true; | |
170 } | |
171 | |
172 if (actions_count == actions_allocated) | |
173 { | |
174 /* Extend the actions array. Note that we cannot use xrealloc(), | |
175 because then the cleanup() function could access an already | |
176 deallocated array. */ | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
177 actions_entry_t *old_actions = actions; |
4770 | 178 size_t new_actions_allocated = 2 * actions_allocated; |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
179 actions_entry_t *new_actions = |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
180 xmalloc (new_actions_allocated * sizeof (actions_entry_t)); |
4770 | 181 |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
182 memcpy (new_actions, old_actions, |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
183 actions_allocated * sizeof (actions_entry_t)); |
4770 | 184 actions = new_actions; |
185 actions_allocated = new_actions_allocated; | |
186 /* Now we can free the old actions array. */ | |
187 if (old_actions != static_actions) | |
188 free (old_actions); | |
189 } | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
190 /* The two uses of 'volatile' in the types above (and ISO C 99 section |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
191 5.1.2.3.(5)) ensure that we increment the actions_count only after |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
192 the new action has been written to the memory location |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
193 actions[actions_count]. */ |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
194 actions[actions_count].action = action; |
4770 | 195 actions_count++; |
196 } | |
197 | |
198 | |
199 /* ========================================================================= */ | |
200 | |
201 | |
202 #if HAVE_POSIX_SIGNALBLOCKING | |
203 | |
204 static sigset_t fatal_signal_set; | |
205 | |
206 static void | |
207 init_fatal_signal_set () | |
208 { | |
209 static bool fatal_signal_set_initialized = false; | |
210 if (!fatal_signal_set_initialized) | |
211 { | |
212 size_t i; | |
213 | |
214 sigemptyset (&fatal_signal_set); | |
215 for (i = 0; i < num_fatal_signals; i++) | |
216 sigaddset (&fatal_signal_set, fatal_signals[i]); | |
217 | |
218 fatal_signal_set_initialized = true; | |
219 } | |
220 } | |
221 | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
222 /* Temporarily delay the catchable fatal signals. */ |
4770 | 223 void |
224 block_fatal_signals () | |
225 { | |
226 init_fatal_signal_set (); | |
227 sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL); | |
228 } | |
229 | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
230 /* Stop delaying the catchable fatal signals. */ |
4770 | 231 void |
232 unblock_fatal_signals () | |
233 { | |
234 init_fatal_signal_set (); | |
235 sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL); | |
236 } | |
237 | |
238 #else | |
239 | |
240 /* Don't bother caring about the old systems which don't have POSIX signal | |
241 blocking. */ | |
242 | |
243 void | |
244 block_fatal_signals () | |
245 { | |
246 } | |
247 | |
248 void | |
249 unblock_fatal_signals () | |
250 { | |
251 } | |
252 | |
253 #endif |