Mercurial > hg > octave-nkf > gnulib-hg
annotate lib/fatal-signal.c @ 7014:43bb3848f1c7
Merge from gettext 0.15: Be more careful to use 'volatile'.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Sat, 22 Jul 2006 14:44:27 +0000 (2006-07-22) |
parents | 1b0092424a44 |
children | 1c4ed7637c24 |
rev | line source |
---|---|
4770 | 1 /* Emergency actions in case of a fatal signal. |
6751
1b0092424a44
Include <unistd.h> unconditionally.
Bruno Haible <bruno@clisp.org>
parents:
6259
diff
changeset
|
2 Copyright (C) 2003-2004, 2006 Free Software Foundation, Inc. |
4770 | 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, | |
5848
a48fb0e98c8c
*** empty log message ***
Paul Eggert <eggert@cs.ucla.edu>
parents:
5537
diff
changeset
|
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
4770 | 18 |
19 | |
20 #ifdef HAVE_CONFIG_H | |
6259
96c32553b4c6
Use a consistent style for including <config.h>.
Paul Eggert <eggert@cs.ucla.edu>
parents:
5848
diff
changeset
|
21 # include <config.h> |
4770 | 22 #endif |
23 | |
24 /* Specification. */ | |
25 #include "fatal-signal.h" | |
26 | |
27 #include <stdbool.h> | |
28 #include <stdlib.h> | |
29 #include <signal.h> | |
6751
1b0092424a44
Include <unistd.h> unconditionally.
Bruno Haible <bruno@clisp.org>
parents:
6259
diff
changeset
|
30 #include <unistd.h> |
4770 | 31 |
32 #include "xalloc.h" | |
33 | |
34 #define SIZEOF(a) (sizeof(a) / sizeof(a[0])) | |
35 | |
36 | |
37 /* ========================================================================= */ | |
38 | |
39 | |
40 /* The list of fatal signals. | |
41 These are those signals whose default action is to terminate the process | |
42 without a core dump, except | |
43 SIGKILL - because it cannot be caught, | |
44 SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications | |
45 often use them for their own purpose, | |
46 SIGPROF SIGVTALRM - because they are used for profiling, | |
47 SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS, | |
48 SIGSYS - because it is more similar to SIGABRT, SIGSEGV, | |
49 SIGPWR - because it of too special use, | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
50 SIGRTMIN...SIGRTMAX - because they are reserved for application use. |
4770 | 51 plus |
52 SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */ | |
53 | |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
54 static int fatal_signals[] = |
4770 | 55 { |
56 /* ISO C 99 signals. */ | |
57 #ifdef SIGINT | |
58 SIGINT, | |
59 #endif | |
60 #ifdef SIGTERM | |
61 SIGTERM, | |
62 #endif | |
63 /* POSIX:2001 signals. */ | |
64 #ifdef SIGHUP | |
65 SIGHUP, | |
66 #endif | |
67 #ifdef SIGPIPE | |
68 SIGPIPE, | |
69 #endif | |
70 /* BSD signals. */ | |
71 #ifdef SIGXCPU | |
72 SIGXCPU, | |
73 #endif | |
74 #ifdef SIGXFSZ | |
75 SIGXFSZ, | |
76 #endif | |
77 0 | |
78 }; | |
79 | |
80 #define num_fatal_signals (SIZEOF (fatal_signals) - 1) | |
81 | |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
82 /* Eliminate signals whose signal handler is SIG_IGN. */ |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
83 |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
84 static void |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
85 init_fatal_signals (void) |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
86 { |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
87 static bool fatal_signals_initialized = false; |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
88 if (!fatal_signals_initialized) |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
89 { |
5537
0fc3beabfb42
Portability fix: Don't assume sigaction(). (mingw doesn't have it.)
Bruno Haible <bruno@clisp.org>
parents:
5536
diff
changeset
|
90 #if HAVE_SIGACTION |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
91 size_t i; |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
92 |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
93 for (i = 0; i < num_fatal_signals; i++) |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
94 { |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
95 struct sigaction action; |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
96 |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
97 if (sigaction (fatal_signals[i], NULL, &action) >= 0 |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
98 && action.sa_handler == SIG_IGN) |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
99 fatal_signals[i] = -1; |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
100 } |
5537
0fc3beabfb42
Portability fix: Don't assume sigaction(). (mingw doesn't have it.)
Bruno Haible <bruno@clisp.org>
parents:
5536
diff
changeset
|
101 #endif |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
102 |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
103 fatal_signals_initialized = true; |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
104 } |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
105 } |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
106 |
4770 | 107 |
108 /* ========================================================================= */ | |
109 | |
110 | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
111 typedef void (*action_t) (void); |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
112 |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
113 /* Type of an entry in the actions array. |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
114 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
|
115 therefore we mark it as 'volatile'. */ |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
116 typedef struct |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
117 { |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
118 volatile action_t action; |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
119 } |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
120 actions_entry_t; |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
121 |
4770 | 122 /* The registered cleanup actions. */ |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
123 static actions_entry_t static_actions[32]; |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
124 static actions_entry_t * volatile actions = static_actions; |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
125 static sig_atomic_t volatile actions_count = 0; |
4770 | 126 static size_t actions_allocated = SIZEOF (static_actions); |
127 | |
128 | |
129 /* Uninstall the handlers. */ | |
130 static inline void | |
131 uninstall_handlers () | |
132 { | |
133 size_t i; | |
134 | |
135 for (i = 0; i < num_fatal_signals; i++) | |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
136 if (fatal_signals[i] >= 0) |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
137 signal (fatal_signals[i], SIG_DFL); |
4770 | 138 } |
139 | |
140 | |
141 /* The signal handler. It gets called asynchronously. */ | |
142 static void | |
143 fatal_signal_handler (int sig) | |
144 { | |
145 for (;;) | |
146 { | |
147 /* Get the last registered cleanup action, in a reentrant way. */ | |
148 action_t action; | |
149 size_t n = actions_count; | |
150 if (n == 0) | |
151 break; | |
152 n--; | |
153 actions_count = n; | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
154 action = actions[n].action; |
4770 | 155 /* Execute the action. */ |
156 action (); | |
157 } | |
158 | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
159 /* Now execute the signal's default action. |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
160 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
|
161 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
|
162 handler returns; otherwise it is delivered already during raise(). */ |
4770 | 163 uninstall_handlers (); |
164 #if HAVE_RAISE | |
165 raise (sig); | |
166 #else | |
167 kill (getpid (), sig); | |
168 #endif | |
169 } | |
170 | |
171 | |
172 /* Install the handlers. */ | |
173 static inline void | |
174 install_handlers () | |
175 { | |
176 size_t i; | |
177 | |
178 for (i = 0; i < num_fatal_signals; i++) | |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
179 if (fatal_signals[i] >= 0) |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
180 signal (fatal_signals[i], &fatal_signal_handler); |
4770 | 181 } |
182 | |
183 | |
184 /* Register a cleanup function to be executed when a catchable fatal signal | |
185 occurs. */ | |
186 void | |
187 at_fatal_signal (action_t action) | |
188 { | |
189 static bool cleanup_initialized = false; | |
190 if (!cleanup_initialized) | |
191 { | |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
192 init_fatal_signals (); |
4770 | 193 install_handlers (); |
194 cleanup_initialized = true; | |
195 } | |
196 | |
197 if (actions_count == actions_allocated) | |
198 { | |
199 /* Extend the actions array. Note that we cannot use xrealloc(), | |
200 because then the cleanup() function could access an already | |
201 deallocated array. */ | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
202 actions_entry_t *old_actions = actions; |
7014
43bb3848f1c7
Merge from gettext 0.15: Be more careful to use 'volatile'.
Bruno Haible <bruno@clisp.org>
parents:
6751
diff
changeset
|
203 size_t old_actions_allocated = actions_allocated; |
4770 | 204 size_t new_actions_allocated = 2 * actions_allocated; |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
205 actions_entry_t *new_actions = |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
206 xmalloc (new_actions_allocated * sizeof (actions_entry_t)); |
7014
43bb3848f1c7
Merge from gettext 0.15: Be more careful to use 'volatile'.
Bruno Haible <bruno@clisp.org>
parents:
6751
diff
changeset
|
207 size_t k; |
4770 | 208 |
7014
43bb3848f1c7
Merge from gettext 0.15: Be more careful to use 'volatile'.
Bruno Haible <bruno@clisp.org>
parents:
6751
diff
changeset
|
209 /* Don't use memcpy() here, because memcpy takes non-volatile arguments |
43bb3848f1c7
Merge from gettext 0.15: Be more careful to use 'volatile'.
Bruno Haible <bruno@clisp.org>
parents:
6751
diff
changeset
|
210 and is therefore not guaranteed to complete all memory stores before |
43bb3848f1c7
Merge from gettext 0.15: Be more careful to use 'volatile'.
Bruno Haible <bruno@clisp.org>
parents:
6751
diff
changeset
|
211 the next statement. */ |
43bb3848f1c7
Merge from gettext 0.15: Be more careful to use 'volatile'.
Bruno Haible <bruno@clisp.org>
parents:
6751
diff
changeset
|
212 for (k = 0; k < old_actions_allocated; k++) |
43bb3848f1c7
Merge from gettext 0.15: Be more careful to use 'volatile'.
Bruno Haible <bruno@clisp.org>
parents:
6751
diff
changeset
|
213 new_actions[k] = old_actions[k]; |
4770 | 214 actions = new_actions; |
215 actions_allocated = new_actions_allocated; | |
216 /* Now we can free the old actions array. */ | |
217 if (old_actions != static_actions) | |
218 free (old_actions); | |
219 } | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
220 /* 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
|
221 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
|
222 the new action has been written to the memory location |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
223 actions[actions_count]. */ |
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
224 actions[actions_count].action = action; |
4770 | 225 actions_count++; |
226 } | |
227 | |
228 | |
229 /* ========================================================================= */ | |
230 | |
231 | |
232 #if HAVE_POSIX_SIGNALBLOCKING | |
233 | |
234 static sigset_t fatal_signal_set; | |
235 | |
236 static void | |
237 init_fatal_signal_set () | |
238 { | |
239 static bool fatal_signal_set_initialized = false; | |
240 if (!fatal_signal_set_initialized) | |
241 { | |
242 size_t i; | |
243 | |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
244 init_fatal_signals (); |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
245 |
4770 | 246 sigemptyset (&fatal_signal_set); |
247 for (i = 0; i < num_fatal_signals; i++) | |
5536
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
248 if (fatal_signals[i] >= 0) |
f64f1da7e350
Signals whose handler is set to SIG_IGN are not fatal.
Bruno Haible <bruno@clisp.org>
parents:
4786
diff
changeset
|
249 sigaddset (&fatal_signal_set, fatal_signals[i]); |
4770 | 250 |
251 fatal_signal_set_initialized = true; | |
252 } | |
253 } | |
254 | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
255 /* Temporarily delay the catchable fatal signals. */ |
4770 | 256 void |
257 block_fatal_signals () | |
258 { | |
259 init_fatal_signal_set (); | |
260 sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL); | |
261 } | |
262 | |
4786
83d8d561903a
Improved 'fatal-signal' module.
Bruno Haible <bruno@clisp.org>
parents:
4770
diff
changeset
|
263 /* Stop delaying the catchable fatal signals. */ |
4770 | 264 void |
265 unblock_fatal_signals () | |
266 { | |
267 init_fatal_signal_set (); | |
268 sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL); | |
269 } | |
270 | |
271 #else | |
272 | |
273 /* Don't bother caring about the old systems which don't have POSIX signal | |
274 blocking. */ | |
275 | |
276 void | |
277 block_fatal_signals () | |
278 { | |
279 } | |
280 | |
281 void | |
282 unblock_fatal_signals () | |
283 { | |
284 } | |
285 | |
286 #endif |