From: Ben Pfaff Date: Wed, 19 Jun 2013 20:07:35 +0000 (-0700) Subject: ovs-thread: Add support for various thread-related assertions. X-Git-Tag: sliver-openvswitch-1.10.90-3~6^2~2 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=728a8b141ff670d0b98b61bd88a6bb7a9c719e26 ovs-thread: Add support for various thread-related assertions. Signed-off-by: Ben Pfaff Acked-by: Ethan Jackson --- diff --git a/lib/command-line.c b/lib/command-line.c index 70b1f4d1b..7800c0b6e 100644 --- a/lib/command-line.c +++ b/lib/command-line.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 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. @@ -19,6 +19,7 @@ #include #include #include +#include "ovs-thread.h" #include "util.h" #include "vlog.h" @@ -110,6 +111,7 @@ proctitle_init(int argc, char **argv) { int i; + assert_single_threaded(); if (!argc || !argv[0]) { /* This situation should never occur, but... */ return; diff --git a/lib/daemon.c b/lib/daemon.c index e12bc14ae..56b32b80b 100644 --- a/lib/daemon.c +++ b/lib/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 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. @@ -29,6 +29,7 @@ #include "fatal-signal.h" #include "dirs.h" #include "lockfile.h" +#include "ovs-thread.h" #include "process.h" #include "socket-util.h" #include "timeval.h" @@ -88,6 +89,7 @@ make_pidfile_name(const char *name) void set_pidfile(const char *name) { + assert_single_threaded(); free(pidfile); pidfile = make_pidfile_name(name); } @@ -280,9 +282,7 @@ daemonize(void) pid_t fork_and_clean_up(void) { - pid_t pid; - - pid = fork(); + pid_t pid = xfork(); if (pid > 0) { /* Running in parent process. */ fatal_signal_fork(); @@ -290,10 +290,7 @@ fork_and_clean_up(void) /* Running in child process. */ time_postfork(); lockfile_postfork(); - } else { - VLOG_FATAL("fork failed (%s)", strerror(errno)); } - return pid; } @@ -504,6 +501,7 @@ close_standard_fds(void) void daemonize_start(void) { + assert_single_threaded(); daemonize_fd = -1; if (detach) { diff --git a/lib/ofp-version-opt.c b/lib/ofp-version-opt.c index 35d79e671..84e83d8e7 100644 --- a/lib/ofp-version-opt.c +++ b/lib/ofp-version-opt.c @@ -1,6 +1,7 @@ #include #include "ofp-util.h" #include "ofp-version-opt.h" +#include "ovs-thread.h" #include "vlog.h" #include "dynamic-string.h" @@ -17,12 +18,14 @@ get_allowed_ofp_versions(void) void set_allowed_ofp_versions(const char *string) { + assert_single_threaded(); allowed_versions = ofputil_versions_from_string(string); } void mask_allowed_ofp_versions(uint32_t bitmap) { + assert_single_threaded(); allowed_versions &= bitmap; } diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c index e1e728912..3ea07b5f4 100644 --- a/lib/ovs-thread.c +++ b/lib/ovs-thread.c @@ -17,7 +17,12 @@ #include #include "ovs-thread.h" #include +#include +#include +#include #include "compiler.h" +#include "poll-loop.h" +#include "socket-util.h" #include "util.h" #ifdef __CHECKER__ @@ -26,6 +31,18 @@ * cut-and-paste. Since "sparse" is just a checker, not a compiler, it * doesn't matter that we don't define them. */ #else +#include "vlog.h" + +VLOG_DEFINE_THIS_MODULE(ovs_thread); + +/* If there is a reason that we cannot fork anymore (unless the fork will be + * immediately followed by an exec), then this points to a string that + * explains why. */ +static const char *must_not_fork; + +/* True if we created any threads beyond the main initial thread. */ +static bool multithreaded; + #define XPTHREAD_FUNC1(FUNCTION, PARAM1) \ void \ x##FUNCTION(PARAM1 arg1) \ @@ -83,6 +100,9 @@ xpthread_create(pthread_t *threadp, pthread_attr_t *attr, pthread_t thread; int error; + forbid_forking("multiple threads exist"); + multithreaded = true; + error = pthread_create(threadp ? threadp : &thread, attr, start, arg); if (error) { ovs_abort(error, "pthread_create failed"); @@ -106,4 +126,52 @@ ovsthread_once_done(struct ovsthread_once *once) atomic_store(&once->done, true); xpthread_mutex_unlock(&once->mutex); } + +/* Asserts that the process has not yet created any threads (beyond the initial + * thread). */ +void +(assert_single_threaded)(const char *where) +{ + if (multithreaded) { + VLOG_FATAL("%s: attempted operation not allowed when multithreaded", + where); + } +} + +/* Forks the current process (checking that this is allowed). Aborts with + * VLOG_FATAL if fork() returns an error, and otherwise returns the value + * returned by fork(). */ +pid_t +(xfork)(const char *where) +{ + pid_t pid; + + if (must_not_fork) { + VLOG_FATAL("%s: attempted to fork but forking not allowed (%s)", + where, must_not_fork); + } + + pid = fork(); + if (pid < 0) { + VLOG_FATAL("fork failed (%s)", strerror(errno)); + } + return pid; +} + +/* Notes that the process must not call fork() from now on, for the specified + * 'reason'. (The process may still fork() if it execs itself immediately + * afterward.) */ +void +forbid_forking(const char *reason) +{ + ovs_assert(reason != NULL); + must_not_fork = reason; +} + +/* Returns true if the process is allowed to fork, false otherwise. */ +bool +may_fork(void) +{ + return !must_not_fork; +} #endif diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h index 05461e201..9c8023e56 100644 --- a/lib/ovs-thread.h +++ b/lib/ovs-thread.h @@ -18,6 +18,8 @@ #define OVS_THREAD_H 1 #include +#include +#include #include "ovs-atomic.h" #include "util.h" @@ -365,5 +367,14 @@ ovsthread_once_start(struct ovsthread_once *once) #define ovsthread_once_start(ONCE) \ ((ONCE)->done ? false : ({ OVS_ACQUIRE(ONCE); true; })) #endif + +void assert_single_threaded(const char *where); +#define assert_single_threaded() assert_single_threaded(SOURCE_LOCATOR) + +pid_t xfork(const char *where); +#define xfork() xfork(SOURCE_LOCATOR) + +void forbid_forking(const char *reason); +bool may_fork(void); #endif /* ovs-thread.h */ diff --git a/lib/process.c b/lib/process.c index 03e00ce1a..266c90b6a 100644 --- a/lib/process.c +++ b/lib/process.c @@ -28,6 +28,7 @@ #include "dynamic-string.h" #include "fatal-signal.h" #include "list.h" +#include "ovs-thread.h" #include "poll-loop.h" #include "signals.h" #include "socket-util.h" @@ -71,6 +72,7 @@ process_init(void) static bool inited; struct sigaction sa; + assert_single_threaded(); if (inited) { return; } @@ -180,6 +182,8 @@ process_start(char **argv, struct process **pp) pid_t pid; int error; + assert_single_threaded(); + *pp = NULL; COVERAGE_INC(process_start); error = process_prestart(argv); diff --git a/lib/timeval.c b/lib/timeval.c index 5ff59bcc1..4723c5686 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -30,6 +30,7 @@ #include "fatal-signal.h" #include "hash.h" #include "hmap.h" +#include "ovs-thread.h" #include "signals.h" #include "unixctl.h" #include "util.h" @@ -297,6 +298,7 @@ time_alarm(unsigned int secs) long long int now; long long int msecs; + assert_single_threaded(); time_init(); time_refresh(); diff --git a/lib/util.c b/lib/util.c index a11841229..29157d31b 100644 --- a/lib/util.c +++ b/lib/util.c @@ -27,6 +27,7 @@ #include #include "byte-order.h" #include "coverage.h" +#include "ovs-thread.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(util); @@ -339,6 +340,9 @@ set_program_name__(const char *argv0, const char *version, const char *date, const char *time) { const char *slash = strrchr(argv0, '/'); + + assert_single_threaded(); + program_name = slash ? slash + 1 : argv0; free(program_version);