summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Scalbert <louis.scalbert@6wind.com>2024-02-02 10:25:05 +0100
committerLouis Scalbert <louis.scalbert@6wind.com>2024-02-02 10:25:05 +0100
commit73f72c52668cb402913ac694d91c25ee48cb174a (patch)
treece756c2ede8bbaf125a2d14076ca7a6716bbc1bc
parenta4f222292ba26dd536da6004772341738b1e9be4 (diff)
lib: add ability to log from external pthread
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>
-rw-r--r--lib/frr_pthread.c31
-rw-r--r--lib/frr_pthread.h3
-rw-r--r--lib/frrcu.c36
-rw-r--r--lib/frrcu.h6
4 files changed, 62 insertions, 14 deletions
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index 761969266a..f7e57136d6 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -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
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
index f91044dfae..1e1b8d7fd3 100644
--- a/lib/frr_pthread.h
+++ b/lib/frr_pthread.h
@@ -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:
diff --git a/lib/frrcu.c b/lib/frrcu.c
index c7cc655e09..b85c525c58 100644
--- a/lib/frrcu.c
+++ b/lib/frrcu.c
@@ -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);
diff --git a/lib/frrcu.h b/lib/frrcu.h
index e7a54dcbe5..9f07a69b52 100644
--- a/lib/frrcu.h
+++ b/lib/frrcu.h
@@ -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.