mirror of
https://github.com/openvswitch/ovs
synced 2025-10-23 14:57:06 +00:00
ovs-thread: Add support for various thread-related assertions.
Signed-off-by: Ben Pfaff <blp@nicira.com> Acked-by: Ethan Jackson <ethan@nicira.com>
This commit is contained in:
@@ -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 <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
|
||||
12
lib/daemon.c
12
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) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <config.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,12 @@
|
||||
#include <config.h>
|
||||
#include "ovs-thread.h"
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#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
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#define OVS_THREAD_H 1
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <unistd.h>
|
||||
#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);
|
||||
|
||||
Reference in New Issue
Block a user