[ovs-dev] [process 4/5] process: Make signal handling thread-safe.
Ben Pfaff
blp at nicira.com
Wed May 8 22:08:15 UTC 2013
Signed-off-by: Ben Pfaff <blp at nicira.com>
---
lib/process.c | 103 ++++++++++++++++----------------------------------
lib/process.h | 1 +
ovsdb/ovsdb-server.c | 7 ++-
3 files changed, 39 insertions(+), 72 deletions(-)
diff --git a/lib/process.c b/lib/process.c
index 5ec888d..eb2d64d 100644
--- a/lib/process.c
+++ b/lib/process.c
@@ -44,9 +44,9 @@ struct process {
char *name;
pid_t pid;
- /* Modified by signal handler. */
- volatile bool exited;
- volatile int status;
+ /* State. */
+ bool exited;
+ int status;
};
/* Pipe used to signal child termination. */
@@ -55,9 +55,6 @@ static int fds[2];
/* All processes. */
static struct list all_processes = LIST_INITIALIZER(&all_processes);
-static bool sigchld_is_blocked(void);
-static void block_sigchld(sigset_t *);
-static void unblock_sigchld(const sigset_t *);
static void sigchld_handler(int signr OVS_UNUSED);
/* Initializes the process subsystem (if it is not already initialized). Calls
@@ -155,8 +152,6 @@ process_register(const char *name, pid_t pid)
struct process *p;
const char *slash;
- ovs_assert(sigchld_is_blocked());
-
p = xzalloc(sizeof *p);
p->pid = pid;
slash = strrchr(name, '/');
@@ -181,7 +176,6 @@ process_register(const char *name, pid_t pid)
int
process_start(char **argv, struct process **pp)
{
- sigset_t oldsigs;
pid_t pid;
int error;
@@ -192,16 +186,13 @@ process_start(char **argv, struct process **pp)
return error;
}
- block_sigchld(&oldsigs);
pid = fork();
if (pid < 0) {
- unblock_sigchld(&oldsigs);
VLOG_WARN("fork failed: %s", strerror(errno));
return errno;
} else if (pid) {
/* Running in parent process. */
*pp = process_register(argv[0], pid);
- unblock_sigchld(&oldsigs);
return 0;
} else {
/* Running in child process. */
@@ -209,7 +200,6 @@ process_start(char **argv, struct process **pp)
int fd;
fatal_signal_fork();
- unblock_sigchld(&oldsigs);
for (fd = 3; fd < fd_max; fd++) {
close(fd);
}
@@ -225,12 +215,7 @@ void
process_destroy(struct process *p)
{
if (p) {
- sigset_t oldsigs;
-
- block_sigchld(&oldsigs);
list_remove(&p->node);
- unblock_sigchld(&oldsigs);
-
free(p->name);
free(p);
}
@@ -265,13 +250,7 @@ process_name(const struct process *p)
bool
process_exited(struct process *p)
{
- if (p->exited) {
- return true;
- } else {
- char buf[_POSIX_PIPE_BUF];
- ignore(read(fds[0], buf, sizeof buf));
- return false;
- }
+ return p->exited;
}
/* Returns process 'p''s exit status, as reported by waitpid(2).
@@ -307,6 +286,35 @@ process_status_msg(int status)
return ds_cstr(&ds);
}
+/* Executes periodic maintenance activities required by the process module. */
+void
+process_run(void)
+{
+ char buf[_POSIX_PIPE_BUF];
+
+ if (!list_is_empty(&all_processes) && read(fds[0], buf, sizeof buf) > 0) {
+ struct process *p;
+
+ LIST_FOR_EACH (p, node, &all_processes) {
+ if (!p->exited) {
+ int retval, status;
+ do {
+ retval = waitpid(p->pid, &status, WNOHANG);
+ } while (retval == -1 && errno == EINTR);
+ if (retval == p->pid) {
+ p->exited = true;
+ p->status = status;
+ } else if (retval < 0) {
+ VLOG_WARN("waitpid: %s", strerror(errno));
+ p->exited = true;
+ p->status = -1;
+ }
+ }
+ }
+ }
+}
+
+
/* Causes the next call to poll_block() to wake up when process 'p' has
* exited. */
void
@@ -347,50 +355,5 @@ process_search_path(const char *name)
static void
sigchld_handler(int signr OVS_UNUSED)
{
- struct process *p;
-
- COVERAGE_INC(process_sigchld);
- LIST_FOR_EACH (p, node, &all_processes) {
- if (!p->exited) {
- int retval, status;
- do {
- retval = waitpid(p->pid, &status, WNOHANG);
- } while (retval == -1 && errno == EINTR);
- if (retval == p->pid) {
- p->exited = true;
- p->status = status;
- } else if (retval < 0) {
- /* XXX We want to log something but we're in a signal
- * handler. */
- p->exited = true;
- p->status = -1;
- }
- }
- }
ignore(write(fds[1], "", 1));
}
-
-static bool
-sigchld_is_blocked(void)
-{
- sigset_t sigs;
-
- xpthread_sigmask(SIG_SETMASK, NULL, &sigs);
- return sigismember(&sigs, SIGCHLD);
-}
-
-static void
-block_sigchld(sigset_t *oldsigs)
-{
- sigset_t sigchld;
-
- sigemptyset(&sigchld);
- sigaddset(&sigchld, SIGCHLD);
- xpthread_sigmask(SIG_BLOCK, &sigchld, oldsigs);
-}
-
-static void
-unblock_sigchld(const sigset_t *oldsigs)
-{
- xpthread_sigmask(SIG_SETMASK, oldsigs, NULL);
-}
diff --git a/lib/process.h b/lib/process.h
index 6d1410b..d17737d 100644
--- a/lib/process.h
+++ b/lib/process.h
@@ -33,6 +33,7 @@ bool process_exited(struct process *);
int process_status(const struct process *);
char *process_status_msg(int);
+void process_run(void);
void process_wait(struct process *);
char *process_search_path(const char *);
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
index b9afd8c..20e1964 100644
--- a/ovsdb/ovsdb-server.c
+++ b/ovsdb/ovsdb-server.c
@@ -230,8 +230,11 @@ main(int argc, char *argv[])
for (i = 0; i < n_dbs; i++) {
ovsdb_trigger_run(dbs[i].db, time_msec());
}
- if (run_process && process_exited(run_process)) {
- exiting = true;
+ if (run_process) {
+ process_run();
+ if (process_exited(run_process)) {
+ exiting = true;
+ }
}
/* update Manager status(es) every 5 seconds */
--
1.7.2.5
More information about the dev
mailing list