urcu-bp: Update fork() handling
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 4 Mar 2011 17:25:08 +0000 (12:25 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 4 Mar 2011 17:26:23 +0000 (12:26 -0500)
Introduce

extern void rcu_bp_before_fork(void);
extern void rcu_bp_after_fork_parent(void);
extern void rcu_bp_after_fork_child(void);

to handle fork gracefully. These disable signals and hold the registry mutex
across forks.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
README
urcu-bp.c
urcu-bp.h

diff --git a/README b/README
index b6d2ae48d0b3365ccd0aa4344bc95f24ed6daef3..f7f0dece2249bb764af9932a35cbf1ca57abffa3 100644 (file)
--- a/README
+++ b/README
@@ -201,6 +201,6 @@ Interaction with fork()
        threads) should be released before a fork() is performed, except for the
        rather common scenario where fork() is immediately followed by exec() in
        the child process. The only implementation not subject to that rule is
-       liburcu-bp, which is designed to handle this case by requiring a call to
-       synchronize_rcu() following the fork() in the child before any new
-       thread is created.
+       liburcu-bp, which is designed to handle fork() by calling
+       rcu_bp_before_fork, rcu_bp_after_fork_parent and
+       rcu_bp_after_fork_child.
index db2aef0c57b8ef397095cd71d6c12ded119bb9ec..04bb6756a2bbe5aa8603c0ed148eae8c95a6be23 100644 (file)
--- a/urcu-bp.c
+++ b/urcu-bp.c
@@ -76,6 +76,9 @@ struct registry_arena {
 
 static struct registry_arena registry_arena;
 
+/* Saved fork signal mask, protected by rcu_gp_lock */
+static sigset_t saved_fork_signal_mask;
+
 static void rcu_gc_registry(void);
 
 static void mutex_lock(pthread_mutex_t *mutex)
@@ -331,3 +334,44 @@ void rcu_bp_exit()
 {
        munmap(registry_arena.p, registry_arena.len);
 }
+
+/*
+ * Holding the rcu_gp_lock across fork will make sure we fork() don't race with
+ * a concurrent thread executing with this same lock held. This ensures that the
+ * registry is in a coherent state in the child.
+ */
+void rcu_bp_before_fork(void)
+{
+       sigset_t newmask, oldmask;
+       int ret;
+
+       ret = sigemptyset(&newmask);
+       assert(!ret);
+       ret = pthread_sigmask(SIG_SETMASK, &newmask, &oldmask);
+       assert(!ret);
+       mutex_lock(&rcu_gp_lock);
+       saved_fork_signal_mask = oldmask;
+}
+
+void rcu_bp_after_fork_parent(void)
+{
+       sigset_t oldmask;
+       int ret;
+
+       oldmask = saved_fork_signal_mask;
+       mutex_unlock(&rcu_gp_lock);
+       ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
+       assert(!ret);
+}
+
+void rcu_bp_after_fork_child(void)
+{
+       sigset_t oldmask;
+       int ret;
+
+       rcu_gc_registry();
+       oldmask = saved_fork_signal_mask;
+       mutex_unlock(&rcu_gp_lock);
+       ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
+       assert(!ret);
+}
index cca664bc906c7fbbedd94dabeb7a1a7195610811..d92fbd1755047cc8cb446f9ec568d6b332f29a16 100644 (file)
--- a/urcu-bp.h
+++ b/urcu-bp.h
@@ -86,6 +86,16 @@ extern void rcu_read_unlock(void);
 
 extern void synchronize_rcu(void);
 
+/*
+ * rcu_bp_before_fork, rcu_bp_after_fork_parent and rcu_bp_after_fork_child
+ * should be called around fork() system calls when the child process is not
+ * expected to immediately perform an exec(). For pthread users, see
+ * pthread_atfork(3).
+ */
+extern void rcu_bp_before_fork(void);
+extern void rcu_bp_after_fork_parent(void);
+extern void rcu_bp_after_fork_child(void);
+
 /*
  * In the bulletproof version, the following functions are no-ops.
  */
This page took 0.026678 seconds and 4 git commands to generate.