]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: add ability to log from external pthread
authorLouis Scalbert <louis.scalbert@6wind.com>
Fri, 2 Feb 2024 09:25:05 +0000 (10:25 +0100)
committerLouis Scalbert <louis.scalbert@6wind.com>
Fri, 2 Feb 2024 09:25:05 +0000 (10:25 +0100)
External libraries can re-enter the FRR code through a hook function. A
crash occurs when logging from this hook function if the library has
initiated a new pthread, as the FRR RCU context is not initialized for
this thread.

Add frr_pthread_non_controlled_startup() function to initialize a valid
RCU context within a FRR pthread context, originating from an external
pthread.

Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
lib/frr_pthread.c
lib/frr_pthread.h
lib/frrcu.c
lib/frrcu.h

index 761969266ae4a7e16a0f7b50a72deff5a2d5c7ad..f7e57136d607ddee519bfa31efe33ff30592e3af 100644 (file)
@@ -220,6 +220,37 @@ void frr_pthread_stop_all(void)
        }
 }
 
+static void *frr_pthread_attr_non_controlled_start(void *arg)
+{
+       struct frr_pthread *fpt = arg;
+
+       fpt->running = true;
+
+       return NULL;
+}
+
+/* Create a FRR pthread context from a non FRR pthread initialized from an
+ * external library in order to allow logging */
+int frr_pthread_non_controlled_startup(pthread_t thread, const char *name,
+                                      const char *os_name)
+{
+       struct frr_pthread_attr attr = {
+               .start = frr_pthread_attr_non_controlled_start,
+               .stop = frr_pthread_attr_default.stop,
+       };
+       struct frr_pthread *fpt;
+
+       fpt = frr_pthread_new(&attr, name, os_name);
+       if (!fpt)
+               return -1;
+
+       fpt->thread = thread;
+       fpt->rcu_thread = rcu_thread_new(NULL);
+       frr_pthread_inner(fpt);
+
+       return 0;
+}
+
 /*
  * ----------------------------------------------------------------------------
  * Default Event Loop
index f91044dfaef2c9e6e0de168e56ab22b5e844492f..1e1b8d7fd3e21dd4618bc2ddd26105d67235be9e 100644 (file)
@@ -202,6 +202,9 @@ void frr_pthread_stop_all(void);
 #define pthread_condattr_setclock(A, B)
 #endif
 
+int frr_pthread_non_controlled_startup(pthread_t thread, const char *name,
+                                      const char *os_name);
+
 /* mutex auto-lock/unlock */
 
 /* variant 1:
index c7cc655e09ceb9339cc5493e973234d2985de209..b85c525c5879d6037049a913f383e19349d22a74 100644 (file)
@@ -149,20 +149,9 @@ static struct rcu_thread *rcu_self(void)
        return (struct rcu_thread *)pthread_getspecific(rcu_thread_key);
 }
 
-/*
- * thread management (for the non-main thread)
- */
-struct rcu_thread *rcu_thread_prepare(void)
+struct rcu_thread *rcu_thread_new(void *arg)
 {
-       struct rcu_thread *rt, *cur;
-
-       rcu_assert_read_locked();
-
-       if (!rcu_active)
-               rcu_start();
-
-       cur = rcu_self();
-       assert(cur->depth);
+       struct rcu_thread *rt, *cur = arg;
 
        /* 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
@@ -172,13 +161,32 @@ struct rcu_thread *rcu_thread_prepare(void)
        rt->depth = 1;
 
        seqlock_init(&rt->rcu);
-       seqlock_acquire(&rt->rcu, &cur->rcu);
+       if (cur)
+               seqlock_acquire(&rt->rcu, &cur->rcu);
 
        rcu_threads_add_tail(&rcu_threads, rt);
 
        return rt;
 }
 
+/*
+ * thread management (for the non-main thread)
+ */
+struct rcu_thread *rcu_thread_prepare(void)
+{
+       struct rcu_thread *cur;
+
+       rcu_assert_read_locked();
+
+       if (!rcu_active)
+               rcu_start();
+
+       cur = rcu_self();
+       assert(cur->depth);
+
+       return rcu_thread_new(cur);
+}
+
 void rcu_thread_start(struct rcu_thread *rt)
 {
        pthread_setspecific(rcu_thread_key, rt);
index e7a54dcbe5d441c2122f9c13106fd5624909cd47..9f07a69b5226abb7ceb519fa6d8019036c3ed71f 100644 (file)
@@ -40,6 +40,12 @@ extern "C" {
 /* opaque */
 struct rcu_thread;
 
+/* sets up rcu thread info
+ *
+ * return value must be passed into the thread's call to rcu_thread_start()
+ */
+extern struct rcu_thread *rcu_thread_new(void *arg);
+
 /* called before new thread creation, sets up rcu thread info for new thread
  * before it actually exits.  This ensures possible RCU references are held
  * for thread startup.