Looks good to me, thanks,
On Thu, Jul 18, 2013 at 4:15 PM, Ben Pfaff <b...@nicira.com> wrote: > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > lib/fatal-signal.c | 56 > +++++++++++++++++++++++++++++++++++++++++++-------- > lib/fatal-signal.h | 3 +- > lib/ovs-thread.c | 5 ++++ > lib/ovs-thread.h | 6 +++++ > 4 files changed, 60 insertions(+), 10 deletions(-) > > diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c > index db8d98e..40daf5a 100644 > --- a/lib/fatal-signal.c > +++ b/lib/fatal-signal.c > @@ -23,6 +23,7 @@ > #include <stdlib.h> > #include <string.h> > #include <unistd.h> > +#include "ovs-thread.h" > #include "poll-loop.h" > #include "shash.h" > #include "sset.h" > @@ -56,20 +57,32 @@ static size_t n_hooks; > static int signal_fds[2]; > static volatile sig_atomic_t stored_sig_nr = SIG_ATOMIC_MAX; > > -static void fatal_signal_init(void); > +static pthread_mutex_t mutex; > + > static void atexit_handler(void); > static void call_hooks(int sig_nr); > > -static void > +/* Initializes the fatal signal handling module. Calling this function is > + * optional, because calling any other function in the module will also > + * initialize it. However, in a multithreaded program, the module must be > + * initialized while the process is still single-threaded. */ > +void > fatal_signal_init(void) > { > static bool inited = false; > > if (!inited) { > + pthread_mutexattr_t attr; > size_t i; > > + assert_single_threaded(); > inited = true; > > + xpthread_mutexattr_init(&attr); > + xpthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); > + xpthread_mutex_init(&mutex, &attr); > + xpthread_mutexattr_destroy(&attr); > + > xpipe_nonblocking(signal_fds); > > for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) { > @@ -86,13 +99,13 @@ fatal_signal_init(void) > } > } > > -/* Registers 'hook_cb' to be called when a process termination signal is > - * raised. If 'run_at_exit' is true, 'hook_cb' is also called during > normal > - * process termination, e.g. when exit() is called or when main() returns. > +/* Registers 'hook_cb' to be called from inside poll_block() following a > fatal > + * signal. 'hook_cb' does not need to be async-signal-safe. In a > + * multithreaded program 'hook_cb' might be called from any thread, with > + * threads other than the one running 'hook_cb' in unknown states. > * > - * 'hook_cb' is not called immediately from the signal handler but rather > the > - * next time the poll loop iterates, so it is freed from the usual > restrictions > - * on signal handler functions. > + * If 'run_at_exit' is true, 'hook_cb' is also called during normal > process > + * termination, e.g. when exit() is called or when main() returns. > * > * If the current process forks, fatal_signal_fork() may be called to > clear the > * parent process's fatal signal hooks, so that 'hook_cb' is only called > when > @@ -106,12 +119,14 @@ fatal_signal_add_hook(void (*hook_cb)(void *aux), > void (*cancel_cb)(void *aux), > { > fatal_signal_init(); > > + xpthread_mutex_lock(&mutex); > ovs_assert(n_hooks < MAX_HOOKS); > hooks[n_hooks].hook_cb = hook_cb; > hooks[n_hooks].cancel_cb = cancel_cb; > hooks[n_hooks].aux = aux; > hooks[n_hooks].run_at_exit = run_at_exit; > n_hooks++; > + xpthread_mutex_unlock(&mutex); > } > > /* Handles fatal signal number 'sig_nr'. > @@ -152,6 +167,8 @@ fatal_signal_run(void) > if (sig_nr != SIG_ATOMIC_MAX) { > char namebuf[SIGNAL_NAME_BUFSIZE]; > > + xpthread_mutex_lock(&mutex); > + > VLOG_WARN("terminating with signal %d (%s)", > (int)sig_nr, signal_name(sig_nr, namebuf, sizeof > namebuf)); > call_hooks(sig_nr); > @@ -160,6 +177,9 @@ fatal_signal_run(void) > * termination status reflects that we were killed by this signal > */ > signal(sig_nr, SIG_DFL); > raise(sig_nr); > + > + xpthread_mutex_unlock(&mutex); > + NOT_REACHED(); > } > } > > @@ -210,12 +230,16 @@ static void do_unlink_files(void); > void > fatal_signal_add_file_to_unlink(const char *file) > { > + fatal_signal_init(); > + > + xpthread_mutex_lock(&mutex); > if (!added_hook) { > added_hook = true; > fatal_signal_add_hook(unlink_files, cancel_files, NULL, true); > } > > sset_add(&files, file); > + xpthread_mutex_unlock(&mutex); > } > > /* Unregisters 'file' from being unlinked when the program terminates via > @@ -223,7 +247,11 @@ fatal_signal_add_file_to_unlink(const char *file) > void > fatal_signal_remove_file_to_unlink(const char *file) > { > + fatal_signal_init(); > + > + xpthread_mutex_lock(&mutex); > sset_find_and_delete(&files, file); > + xpthread_mutex_unlock(&mutex); > } > > /* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'. > @@ -231,13 +259,21 @@ fatal_signal_remove_file_to_unlink(const char *file) > int > fatal_signal_unlink_file_now(const char *file) > { > - int error = unlink(file) ? errno : 0; > + int error; > + > + fatal_signal_init(); > + > + xpthread_mutex_lock(&mutex); > + > + error = unlink(file) ? errno : 0; > if (error) { > VLOG_WARN("could not unlink \"%s\" (%s)", file, > ovs_strerror(error)); > } > > fatal_signal_remove_file_to_unlink(file); > > + xpthread_mutex_unlock(&mutex); > + > return error; > } > > @@ -277,6 +313,8 @@ fatal_signal_fork(void) > { > size_t i; > > + assert_single_threaded(); > + > for (i = 0; i < n_hooks; i++) { > struct hook *h = &hooks[i]; > if (h->cancel_cb) { > diff --git a/lib/fatal-signal.h b/lib/fatal-signal.h > index 8a1a84b..b458d3d 100644 > --- a/lib/fatal-signal.h > +++ b/lib/fatal-signal.h > @@ -1,5 +1,5 @@ > /* > - * Copyright (c) 2008, 2009, 2010 Nicira, Inc. > + * Copyright (c) 2008, 2009, 2010, 2013 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -20,6 +20,7 @@ > #include <stdbool.h> > > /* Basic interface. */ > +void fatal_signal_init(void); > void fatal_signal_add_hook(void (*hook_cb)(void *aux), > void (*cancel_cb)(void *aux), void *aux, > bool run_at_exit); > diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c > index d08751c..4776587 100644 > --- a/lib/ovs-thread.c > +++ b/lib/ovs-thread.c > @@ -77,6 +77,11 @@ XPTHREAD_FUNC1(pthread_mutex_lock, pthread_mutex_t *); > XPTHREAD_FUNC1(pthread_mutex_unlock, pthread_mutex_t *); > XPTHREAD_TRY_FUNC1(pthread_mutex_trylock, pthread_mutex_t *); > > +XPTHREAD_FUNC1(pthread_mutexattr_init, pthread_mutexattr_t *); > +XPTHREAD_FUNC1(pthread_mutexattr_destroy, pthread_mutexattr_t *); > +XPTHREAD_FUNC2(pthread_mutexattr_settype, pthread_mutexattr_t *, int); > +XPTHREAD_FUNC2(pthread_mutexattr_gettype, pthread_mutexattr_t *, int *); > + > XPTHREAD_FUNC2(pthread_rwlock_init, > pthread_rwlock_t *, pthread_rwlockattr_t *); > XPTHREAD_FUNC1(pthread_rwlock_rdlock, pthread_rwlock_t *); > diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h > index 9c8023e..b18447d 100644 > --- a/lib/ovs-thread.h > +++ b/lib/ovs-thread.h > @@ -56,11 +56,17 @@ > * process with an error message on any error. The *_trylock() functions > are > * exceptions: they pass through a 0 or EBUSY return value to the caller > and > * abort on any other error. */ > + > void xpthread_mutex_init(pthread_mutex_t *, pthread_mutexattr_t *); > void xpthread_mutex_lock(pthread_mutex_t *mutex) OVS_ACQUIRES(mutex); > void xpthread_mutex_unlock(pthread_mutex_t *mutex) OVS_RELEASES(mutex); > int xpthread_mutex_trylock(pthread_mutex_t *); > > +void xpthread_mutexattr_init(pthread_mutexattr_t *); > +void xpthread_mutexattr_destroy(pthread_mutexattr_t *); > +void xpthread_mutexattr_settype(pthread_mutexattr_t *, int type); > +void xpthread_mutexattr_gettype(pthread_mutexattr_t *, int *typep); > + > void xpthread_rwlock_init(pthread_rwlock_t *, pthread_rwlockattr_t *); > void xpthread_rwlock_rdlock(pthread_rwlock_t *rwlock) > OVS_ACQUIRES(rwlock); > void xpthread_rwlock_wrlock(pthread_rwlock_t *rwlock) > OVS_ACQUIRES(rwlock); > -- > 1.7.2.5 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev >
_______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev