fatal-signal: Remove write-only variable fatal_signal_set.
[sliver-openvswitch.git] / lib / fatal-signal.c
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <config.h>
17 #include "fatal-signal.h"
18 #include <errno.h>
19 #include <signal.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include "poll-loop.h"
27 #include "shash.h"
28 #include "sset.h"
29 #include "signals.h"
30 #include "socket-util.h"
31 #include "util.h"
32 #include "vlog.h"
33
34 #include "type-props.h"
35
36 #ifndef SIG_ATOMIC_MAX
37 #define SIG_ATOMIC_MAX TYPE_MAXIMUM(sig_atomic_t)
38 #endif
39
40 VLOG_DEFINE_THIS_MODULE(fatal_signal);
41
42 /* Signals to catch. */
43 static const int fatal_signals[] = { SIGTERM, SIGINT, SIGHUP, SIGALRM };
44
45 /* Hooks to call upon catching a signal */
46 struct hook {
47     void (*hook_cb)(void *aux);
48     void (*cancel_cb)(void *aux);
49     void *aux;
50     bool run_at_exit;
51 };
52 #define MAX_HOOKS 32
53 static struct hook hooks[MAX_HOOKS];
54 static size_t n_hooks;
55
56 static int signal_fds[2];
57 static volatile sig_atomic_t stored_sig_nr = SIG_ATOMIC_MAX;
58
59 static void fatal_signal_init(void);
60 static void atexit_handler(void);
61 static void call_hooks(int sig_nr);
62
63 static void
64 fatal_signal_init(void)
65 {
66     static bool inited = false;
67
68     if (!inited) {
69         size_t i;
70
71         inited = true;
72
73         xpipe_nonblocking(signal_fds);
74
75         for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) {
76             int sig_nr = fatal_signals[i];
77             struct sigaction old_sa;
78
79             xsigaction(sig_nr, NULL, &old_sa);
80             if (old_sa.sa_handler == SIG_DFL
81                 && signal(sig_nr, fatal_signal_handler) == SIG_ERR) {
82                 VLOG_FATAL("signal failed (%s)", ovs_strerror(errno));
83             }
84         }
85         atexit(atexit_handler);
86     }
87 }
88
89 /* Registers 'hook_cb' to be called when a process termination signal is
90  * raised.  If 'run_at_exit' is true, 'hook_cb' is also called during normal
91  * process termination, e.g. when exit() is called or when main() returns.
92  *
93  * 'hook_cb' is not called immediately from the signal handler but rather the
94  * next time the poll loop iterates, so it is freed from the usual restrictions
95  * on signal handler functions.
96  *
97  * If the current process forks, fatal_signal_fork() may be called to clear the
98  * parent process's fatal signal hooks, so that 'hook_cb' is only called when
99  * the child terminates, not when the parent does.  When fatal_signal_fork() is
100  * called, it calls the 'cancel_cb' function if it is nonnull, passing 'aux',
101  * to notify that the hook has been canceled.  This allows the hook to free
102  * memory, etc. */
103 void
104 fatal_signal_add_hook(void (*hook_cb)(void *aux), void (*cancel_cb)(void *aux),
105                       void *aux, bool run_at_exit)
106 {
107     fatal_signal_init();
108
109     ovs_assert(n_hooks < MAX_HOOKS);
110     hooks[n_hooks].hook_cb = hook_cb;
111     hooks[n_hooks].cancel_cb = cancel_cb;
112     hooks[n_hooks].aux = aux;
113     hooks[n_hooks].run_at_exit = run_at_exit;
114     n_hooks++;
115 }
116
117 /* Handles fatal signal number 'sig_nr'.
118  *
119  * Ordinarily this is the actual signal handler.  When other code needs to
120  * handle one of our signals, however, it can register for that signal and, if
121  * and when necessary, call this function to do fatal signal processing for it
122  * and terminate the process.  Currently only timeval.c does this, for SIGALRM.
123  * (It is not important whether the other code sets up its signal handler
124  * before or after this file, because this file will only set up a signal
125  * handler in the case where the signal has its default handling.)  */
126 void
127 fatal_signal_handler(int sig_nr)
128 {
129     ignore(write(signal_fds[1], "", 1));
130     stored_sig_nr = sig_nr;
131 }
132
133 /* Check whether a fatal signal has occurred and, if so, call the fatal signal
134  * hooks and exit.
135  *
136  * This function is called automatically by poll_block(), but specialized
137  * programs that may not always call poll_block() on a regular basis should
138  * also call it periodically.  (Therefore, any function with "block" in its
139  * name should call fatal_signal_run() each time it is called, either directly
140  * or through poll_block(), because such functions can only used by specialized
141  * programs that can afford to block outside their main loop around
142  * poll_block().)
143  */
144 void
145 fatal_signal_run(void)
146 {
147     sig_atomic_t sig_nr;
148
149     fatal_signal_init();
150
151     sig_nr = stored_sig_nr;
152     if (sig_nr != SIG_ATOMIC_MAX) {
153         char namebuf[SIGNAL_NAME_BUFSIZE];
154
155         VLOG_WARN("terminating with signal %d (%s)",
156                   (int)sig_nr, signal_name(sig_nr, namebuf, sizeof namebuf));
157         call_hooks(sig_nr);
158
159         /* Re-raise the signal with the default handling so that the program
160          * termination status reflects that we were killed by this signal */
161         signal(sig_nr, SIG_DFL);
162         raise(sig_nr);
163     }
164 }
165
166 void
167 fatal_signal_wait(void)
168 {
169     fatal_signal_init();
170     poll_fd_wait(signal_fds[0], POLLIN);
171 }
172
173 static void
174 atexit_handler(void)
175 {
176     call_hooks(0);
177 }
178
179 static void
180 call_hooks(int sig_nr)
181 {
182     static volatile sig_atomic_t recurse = 0;
183     if (!recurse) {
184         size_t i;
185
186         recurse = 1;
187
188         for (i = 0; i < n_hooks; i++) {
189             struct hook *h = &hooks[i];
190             if (sig_nr || h->run_at_exit) {
191                 h->hook_cb(h->aux);
192             }
193         }
194     }
195 }
196 \f
197 /* Files to delete on exit. */
198 static struct sset files = SSET_INITIALIZER(&files);
199
200 /* Has a hook function been registered with fatal_signal_add_hook() (and not
201  * cleared by fatal_signal_fork())? */
202 static bool added_hook;
203
204 static void unlink_files(void *aux);
205 static void cancel_files(void *aux);
206 static void do_unlink_files(void);
207
208 /* Registers 'file' to be unlinked when the program terminates via exit() or a
209  * fatal signal. */
210 void
211 fatal_signal_add_file_to_unlink(const char *file)
212 {
213     if (!added_hook) {
214         added_hook = true;
215         fatal_signal_add_hook(unlink_files, cancel_files, NULL, true);
216     }
217
218     sset_add(&files, file);
219 }
220
221 /* Unregisters 'file' from being unlinked when the program terminates via
222  * exit() or a fatal signal. */
223 void
224 fatal_signal_remove_file_to_unlink(const char *file)
225 {
226     sset_find_and_delete(&files, file);
227 }
228
229 /* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'.
230  * Returns 0 if successful, otherwise a positive errno value. */
231 int
232 fatal_signal_unlink_file_now(const char *file)
233 {
234     int error = unlink(file) ? errno : 0;
235     if (error) {
236         VLOG_WARN("could not unlink \"%s\" (%s)", file, ovs_strerror(error));
237     }
238
239     fatal_signal_remove_file_to_unlink(file);
240
241     return error;
242 }
243
244 static void
245 unlink_files(void *aux OVS_UNUSED)
246 {
247     do_unlink_files();
248 }
249
250 static void
251 cancel_files(void *aux OVS_UNUSED)
252 {
253     sset_clear(&files);
254     added_hook = false;
255 }
256
257 static void
258 do_unlink_files(void)
259 {
260     const char *file;
261
262     SSET_FOR_EACH (file, &files) {
263         unlink(file);
264     }
265 }
266 \f
267 /* Clears all of the fatal signal hooks without executing them.  If any of the
268  * hooks passed a 'cancel_cb' function to fatal_signal_add_hook(), then those
269  * functions will be called, allowing them to free resources, etc.
270  *
271  * Following a fork, one of the resulting processes can call this function to
272  * allow it to terminate without calling the hooks registered before calling
273  * this function.  New hooks registered after calling this function will take
274  * effect normally. */
275 void
276 fatal_signal_fork(void)
277 {
278     size_t i;
279
280     for (i = 0; i < n_hooks; i++) {
281         struct hook *h = &hooks[i];
282         if (h->cancel_cb) {
283             h->cancel_cb(h->aux);
284         }
285     }
286     n_hooks = 0;
287
288     /* Raise any signals that we have already received with the default
289      * handler. */
290     if (stored_sig_nr != SIG_ATOMIC_MAX) {
291         raise(stored_sig_nr);
292     }
293 }