Commit 26df7f3613 for frr

commit 26df7f3613558019b897006f1e7e21df4f045f2e
Author: Christian Hopps <chopps@labn.net>
Date:   Sat Oct 10 05:09:19 2026 -0400

    lib: need lock to make thread safe

    Without the lock if multiple external threads all call rcu_thread_new()
    in parallel we can end up with more than 1 call to rcu_start().

    Signed-off-by: Christian Hopps <chopps@labn.net>

diff --git a/lib/frrcu.c b/lib/frrcu.c
index fea1731b2b..1d2f78620d 100644
--- a/lib/frrcu.c
+++ b/lib/frrcu.c
@@ -111,6 +111,7 @@ static struct rcu_thread rcu_thread_main;
 static struct rcu_thread rcu_thread_rcu;

 static pthread_t rcu_pthread;
+static pthread_mutex_t rcu_start_mtx = PTHREAD_MUTEX_INITIALIZER;
 static pthread_key_t rcu_thread_key;
 static bool rcu_active;

@@ -158,10 +159,14 @@ struct rcu_thread *rcu_thread_new(void *arg)
 	struct rcu_thread *rt, *cur = arg;

 	/* Ensure the sweeper exists so deferred frees from thread teardown
-	 * (and any RCU use on the new thread) actually complete.
+	 * (and any RCU use on the new thread) actually complete.  External
+	 * threads may register concurrently, so serialize the check + start,
+	 * otherwise more than one sweeper gets started.
 	 */
+	pthread_mutex_lock(&rcu_start_mtx);
 	if (!rcu_active)
 		rcu_start();
+	pthread_mutex_unlock(&rcu_start_mtx);

 	/* new thread always starts with rcu_read_lock held at depth 1, and
 	 * holding the same epoch as the parent (this makes it possible to