[ltt-dev] [PATCH RFC urcu] add pthread_atfork interfaces for call_rcu

Paul E. McKenney paulmck at linux.vnet.ibm.com
Sun Mar 13 03:36:46 EDT 2011


Hello!

Please see below for an RFC patch for creating pthread_atfork()-friendly
interfaces for call_rcu().

However, I ran into a problem when trying to test this.  I cannot use
this except with rcu-bp, since only rcu-bp can be made fork()-safe.
OK, easy enough to create the corresponding interfaces for the other
flavors of RCU.  But this led to a couple of issues:

1.	Do we intend to support mixing multiple flavors of RCU in the
	same program?  Trying this with the current implementations
	results in symbol collisions (multiple different versions
	of synchronize_rcu(), for example).  It is possible to use
	preprocessor magic to handle this, but thought I should check
	on the intent before attempting this.

2.	Do we intend to support use of RCU from library functions?
	If the answer is "yes", then we are pretty much stuck supporting
	multiple flavors of RCU in the same program, because different
	library functions might reasonably choose different of the
	RCU implementations.

3.	Do we intend to support use of UST on programs that use
	userspace-rcu?  If so, we again might need to tolerate mixing
	of RCU flavors, given that UST uses rcu-bp and the programs
	in questions might reasonably make a different choice.

4.	Do we intend to support use of a given flavor of RCU from
	multiple library modules, such that a given program might
	link any number of the RCU-using library modules?  If so,
	we need initialization to be idempotent.

5.	Do we intend to support use of a given flavor of RCU from
	multiple library modules, some of which might fork() and others
	of which might not?  If so, we need to pull the handling of
	pthread_atfork() into the userspace-rcu library -- otherwise,
	multiple users of RCU might call pthread_atfork(), resulting
	in self-deadlock at fork() time.

	Perhaps a flag on rcu_register_thread() indicating that the
	thread registering itself might fork()?  Or, for compatibility,
	a new rcu_register_thread_flags() that has a bitfield with
	options.  The first thread that indicated that it might fork
	would then cause userspace-rcu to do the required calls to
	pthread_atfork().

I suspect that the answer is "yes" for all of the above questions.

Does this all make sense, or am I confused?

							Thanx, Paul

------------------------------------------------------------------------

Provide pthread_atfork-friendly interfaces

Provides call_rcu_before_fork() and call_rcu_after_fork_parent() to
go with the existing call_rcu_after_fork_child().

Signed-off-by: Paul E. McKenney <paulmck at linux.vnet.ibm.com>

diff --git a/README b/README
index f7f0dec..56e98d7 100644
--- a/README
+++ b/README
@@ -204,3 +204,7 @@ Interaction with fork()
 	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.
+
+	Applications that use call_rcu() are required to invoke
+	call_rcu_after_fork_child() from the child process after a
+	successful fork() system call that is not followed by exec().
diff --git a/urcu-call-rcu.c b/urcu-call-rcu.c
index bb56dbb..665f20c 100644
--- a/urcu-call-rcu.c
+++ b/urcu-call-rcu.c
@@ -566,13 +566,40 @@ void free_all_cpu_call_rcu_data(void)
 }
 
 /*
+ * Acquire the call_rcu_mutex in order to ensure that the child sees
+ * all of the call_rcu() data structures in a consistent state.
+ * Suitable for pthread_atfork() and friends.
+ */
+void call_rcu_before_fork(void)
+{
+	call_rcu_lock(&call_rcu_mutex);
+}
+
+/*
+ * Clean up call_rcu data structures in the parent of a successful fork()
+ * that is not followed by exec() in the child.  Suitable for
+ * pthread_atfork() and friends.
+ */
+void call_rcu_after_fork_parent(void)
+{
+	call_rcu_unlock(&call_rcu_mutex);
+}
+
+/*
  * Clean up call_rcu data structures in the child of a successful fork()
- * that is not followed by exec().
+ * that is not followed by exec().  Suitable for pthread_atfork() and
+ * friends.
  */
 void call_rcu_after_fork_child(void)
 {
 	struct call_rcu_data *crdp;
 
+	/* Re-initialize the mutex. */
+	if (pthread_mutex_init(&call_rcu_mutex, NULL) != 0) {
+		perror("pthread_mutex_init");
+		exit(-1);
+	}
+
 	/*
 	 * Allocate a new default call_rcu_data structure in order
 	 * to get a working call_rcu thread to go with it.




More information about the lttng-dev mailing list