1 /* Emergency actions in case of a fatal signal.
2 Copyright (C) 2003-2004, 2006 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
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)
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23 #include "fatal-signal.h"
32 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
35 /* ========================================================================= */
38 /* The list of fatal signals.
39 These are those signals whose default action is to terminate the process
40 without a core dump, except
41 SIGKILL - because it cannot be caught,
42 SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications
43 often use them for their own purpose,
44 SIGPROF SIGVTALRM - because they are used for profiling,
45 SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS,
46 SIGSYS - because it is more similar to SIGABRT, SIGSEGV,
47 SIGPWR - because it of too special use,
48 SIGRTMIN...SIGRTMAX - because they are reserved for application use.
50 SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */
52 static int fatal_signals[] =
54 /* ISO C 99 signals. */
61 /* POSIX:2001 signals. */
82 #define num_fatal_signals (SIZEOF (fatal_signals) - 1)
84 /* Eliminate signals whose signal handler is SIG_IGN. */
87 init_fatal_signals (void)
89 static bool fatal_signals_initialized = false;
90 if (!fatal_signals_initialized)
95 for (i = 0; i < num_fatal_signals; i++)
97 struct sigaction action;
99 if (sigaction (fatal_signals[i], NULL, &action) >= 0
100 && action.sa_handler == SIG_IGN)
101 fatal_signals[i] = -1;
105 fatal_signals_initialized = true;
110 /* ========================================================================= */
113 typedef void (*action_t) (void);
115 /* Type of an entry in the actions array.
116 The 'action' field is accessed from within the fatal_signal_handler(),
117 therefore we mark it as 'volatile'. */
120 volatile action_t action;
124 /* The registered cleanup actions. */
125 static actions_entry_t static_actions[32];
126 static actions_entry_t * volatile actions = static_actions;
127 static sig_atomic_t volatile actions_count = 0;
128 static size_t actions_allocated = SIZEOF (static_actions);
131 /* Uninstall the handlers. */
133 uninstall_handlers ()
137 for (i = 0; i < num_fatal_signals; i++)
138 if (fatal_signals[i] >= 0)
139 signal (fatal_signals[i], SIG_DFL);
143 /* The signal handler. It gets called asynchronously. */
145 fatal_signal_handler (int sig)
149 /* Get the last registered cleanup action, in a reentrant way. */
151 size_t n = actions_count;
156 action = actions[n].action;
157 /* Execute the action. */
161 /* Now execute the signal's default action.
162 If signal() blocks the signal being delivered for the duration of the
163 signal handler's execution, the re-raised signal is delivered when this
164 handler returns; otherwise it is delivered already during raise(). */
165 uninstall_handlers ();
169 kill (getpid (), sig);
174 /* Install the handlers. */
180 for (i = 0; i < num_fatal_signals; i++)
181 if (fatal_signals[i] >= 0)
182 signal (fatal_signals[i], &fatal_signal_handler);
186 /* Register a cleanup function to be executed when a catchable fatal signal
189 at_fatal_signal (action_t action)
191 static bool cleanup_initialized = false;
192 if (!cleanup_initialized)
194 init_fatal_signals ();
196 cleanup_initialized = true;
199 if (actions_count == actions_allocated)
201 /* Extend the actions array. Note that we cannot use xrealloc(),
202 because then the cleanup() function could access an already
203 deallocated array. */
204 actions_entry_t *old_actions = actions;
205 size_t old_actions_allocated = actions_allocated;
206 size_t new_actions_allocated = 2 * actions_allocated;
207 actions_entry_t *new_actions =
208 xmalloc (new_actions_allocated * sizeof (actions_entry_t));
211 /* Don't use memcpy() here, because memcpy takes non-volatile arguments
212 and is therefore not guaranteed to complete all memory stores before
213 the next statement. */
214 for (k = 0; k < old_actions_allocated; k++)
215 new_actions[k] = old_actions[k];
216 actions = new_actions;
217 actions_allocated = new_actions_allocated;
218 /* Now we can free the old actions array. */
219 if (old_actions != static_actions)
222 /* The two uses of 'volatile' in the types above (and ISO C 99 section
223 5.1.2.3.(5)) ensure that we increment the actions_count only after
224 the new action has been written to the memory location
225 actions[actions_count]. */
226 actions[actions_count].action = action;
231 /* ========================================================================= */
234 #if HAVE_POSIX_SIGNALBLOCKING
236 static sigset_t fatal_signal_set;
239 init_fatal_signal_set ()
241 static bool fatal_signal_set_initialized = false;
242 if (!fatal_signal_set_initialized)
246 init_fatal_signals ();
248 sigemptyset (&fatal_signal_set);
249 for (i = 0; i < num_fatal_signals; i++)
250 if (fatal_signals[i] >= 0)
251 sigaddset (&fatal_signal_set, fatal_signals[i]);
253 fatal_signal_set_initialized = true;
257 /* Temporarily delay the catchable fatal signals. */
259 block_fatal_signals ()
261 init_fatal_signal_set ();
262 sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
265 /* Stop delaying the catchable fatal signals. */
267 unblock_fatal_signals ()
269 init_fatal_signal_set ();
270 sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
275 /* Don't bother caring about the old systems which don't have POSIX signal
279 block_fatal_signals ()
284 unblock_fatal_signals ()