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
        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;
 
 
 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)
 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);
 }
 {
        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);
 
 
 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.
  */
 /*
  * In the bulletproof version, the following functions are no-ops.
  */
This page took 0.026504 seconds and 4 git commands to generate.