Skip to content

Commit

Permalink
lib: add ability to log from external pthread
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
louis-6wind committed Feb 2, 2024
1 parent a4f2222 commit 73f72c5
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 14 deletions.
31 changes: 31 additions & 0 deletions lib/frr_pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions lib/frr_pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
36 changes: 22 additions & 14 deletions lib/frrcu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions lib/frrcu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 73f72c5

Please sign in to comment.