~james-page/ubuntu/saucy/openvswitch/1.12-snapshot

« back to all changes in this revision

Viewing changes to lib/fatal-signal.c

  • Committer: James Page
  • Date: 2013-08-21 10:16:57 UTC
  • mfrom: (1.1.20)
  • Revision ID: james.page@canonical.com-20130821101657-3o0z0qeiv5zkwlzi
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
 
2
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
3
3
 *
4
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
5
 * you may not use this file except in compliance with the License.
23
23
#include <stdlib.h>
24
24
#include <string.h>
25
25
#include <unistd.h>
 
26
#include "ovs-thread.h"
26
27
#include "poll-loop.h"
27
28
#include "shash.h"
28
29
#include "sset.h"
42
43
/* Signals to catch. */
43
44
static const int fatal_signals[] = { SIGTERM, SIGINT, SIGHUP, SIGALRM };
44
45
 
45
 
/* Signals to catch as a sigset_t. */
46
 
static sigset_t fatal_signal_set;
47
 
 
48
46
/* Hooks to call upon catching a signal */
49
47
struct hook {
50
48
    void (*hook_cb)(void *aux);
59
57
static int signal_fds[2];
60
58
static volatile sig_atomic_t stored_sig_nr = SIG_ATOMIC_MAX;
61
59
 
62
 
static void fatal_signal_init(void);
 
60
static struct ovs_mutex mutex;
 
61
 
63
62
static void atexit_handler(void);
64
63
static void call_hooks(int sig_nr);
65
64
 
66
 
static void
 
65
/* Initializes the fatal signal handling module.  Calling this function is
 
66
 * optional, because calling any other function in the module will also
 
67
 * initialize it.  However, in a multithreaded program, the module must be
 
68
 * initialized while the process is still single-threaded. */
 
69
void
67
70
fatal_signal_init(void)
68
71
{
69
72
    static bool inited = false;
71
74
    if (!inited) {
72
75
        size_t i;
73
76
 
 
77
        assert_single_threaded();
74
78
        inited = true;
75
79
 
 
80
        ovs_mutex_init(&mutex, PTHREAD_MUTEX_RECURSIVE);
76
81
        xpipe_nonblocking(signal_fds);
77
82
 
78
 
        sigemptyset(&fatal_signal_set);
79
83
        for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) {
80
84
            int sig_nr = fatal_signals[i];
81
85
            struct sigaction old_sa;
82
86
 
83
 
            sigaddset(&fatal_signal_set, sig_nr);
84
87
            xsigaction(sig_nr, NULL, &old_sa);
85
88
            if (old_sa.sa_handler == SIG_DFL
86
89
                && signal(sig_nr, fatal_signal_handler) == SIG_ERR) {
87
 
                VLOG_FATAL("signal failed (%s)", strerror(errno));
 
90
                VLOG_FATAL("signal failed (%s)", ovs_strerror(errno));
88
91
            }
89
92
        }
90
93
        atexit(atexit_handler);
91
94
    }
92
95
}
93
96
 
94
 
/* Registers 'hook_cb' to be called when a process termination signal is
95
 
 * raised.  If 'run_at_exit' is true, 'hook_cb' is also called during normal
96
 
 * process termination, e.g. when exit() is called or when main() returns.
 
97
/* Registers 'hook_cb' to be called from inside poll_block() following a fatal
 
98
 * signal.  'hook_cb' does not need to be async-signal-safe.  In a
 
99
 * multithreaded program 'hook_cb' might be called from any thread, with
 
100
 * threads other than the one running 'hook_cb' in unknown states.
97
101
 *
98
 
 * 'hook_cb' is not called immediately from the signal handler but rather the
99
 
 * next time the poll loop iterates, so it is freed from the usual restrictions
100
 
 * on signal handler functions.
 
102
 * If 'run_at_exit' is true, 'hook_cb' is also called during normal process
 
103
 * termination, e.g. when exit() is called or when main() returns.
101
104
 *
102
105
 * If the current process forks, fatal_signal_fork() may be called to clear the
103
106
 * parent process's fatal signal hooks, so that 'hook_cb' is only called when
111
114
{
112
115
    fatal_signal_init();
113
116
 
 
117
    ovs_mutex_lock(&mutex);
114
118
    ovs_assert(n_hooks < MAX_HOOKS);
115
119
    hooks[n_hooks].hook_cb = hook_cb;
116
120
    hooks[n_hooks].cancel_cb = cancel_cb;
117
121
    hooks[n_hooks].aux = aux;
118
122
    hooks[n_hooks].run_at_exit = run_at_exit;
119
123
    n_hooks++;
 
124
    ovs_mutex_unlock(&mutex);
120
125
}
121
126
 
122
127
/* Handles fatal signal number 'sig_nr'.
155
160
 
156
161
    sig_nr = stored_sig_nr;
157
162
    if (sig_nr != SIG_ATOMIC_MAX) {
 
163
        char namebuf[SIGNAL_NAME_BUFSIZE];
 
164
 
 
165
        ovs_mutex_lock(&mutex);
 
166
 
158
167
        VLOG_WARN("terminating with signal %d (%s)",
159
 
                  (int)sig_nr, signal_name(sig_nr));
 
168
                  (int)sig_nr, signal_name(sig_nr, namebuf, sizeof namebuf));
160
169
        call_hooks(sig_nr);
161
170
 
162
171
        /* Re-raise the signal with the default handling so that the program
163
172
         * termination status reflects that we were killed by this signal */
164
173
        signal(sig_nr, SIG_DFL);
165
174
        raise(sig_nr);
 
175
 
 
176
        ovs_mutex_unlock(&mutex);
 
177
        NOT_REACHED();
166
178
    }
167
179
}
168
180
 
213
225
void
214
226
fatal_signal_add_file_to_unlink(const char *file)
215
227
{
 
228
    fatal_signal_init();
 
229
 
 
230
    ovs_mutex_lock(&mutex);
216
231
    if (!added_hook) {
217
232
        added_hook = true;
218
233
        fatal_signal_add_hook(unlink_files, cancel_files, NULL, true);
219
234
    }
220
235
 
221
236
    sset_add(&files, file);
 
237
    ovs_mutex_unlock(&mutex);
222
238
}
223
239
 
224
240
/* Unregisters 'file' from being unlinked when the program terminates via
226
242
void
227
243
fatal_signal_remove_file_to_unlink(const char *file)
228
244
{
 
245
    fatal_signal_init();
 
246
 
 
247
    ovs_mutex_lock(&mutex);
229
248
    sset_find_and_delete(&files, file);
 
249
    ovs_mutex_unlock(&mutex);
230
250
}
231
251
 
232
252
/* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'.
234
254
int
235
255
fatal_signal_unlink_file_now(const char *file)
236
256
{
237
 
    int error = unlink(file) ? errno : 0;
 
257
    int error;
 
258
 
 
259
    fatal_signal_init();
 
260
 
 
261
    ovs_mutex_lock(&mutex);
 
262
 
 
263
    error = unlink(file) ? errno : 0;
238
264
    if (error) {
239
 
        VLOG_WARN("could not unlink \"%s\" (%s)", file, strerror(error));
 
265
        VLOG_WARN("could not unlink \"%s\" (%s)", file, ovs_strerror(error));
240
266
    }
241
267
 
242
268
    fatal_signal_remove_file_to_unlink(file);
243
269
 
 
270
    ovs_mutex_unlock(&mutex);
 
271
 
244
272
    return error;
245
273
}
246
274
 
280
308
{
281
309
    size_t i;
282
310
 
 
311
    assert_single_threaded();
 
312
 
283
313
    for (i = 0; i < n_hooks; i++) {
284
314
        struct hook *h = &hooks[i];
285
315
        if (h->cancel_cb) {