mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-26 00:00:50 +00:00
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>
This commit is contained in:
parent
a4f222292b
commit
73f72c5266
@ -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
|
* Default Event Loop
|
||||||
|
@ -202,6 +202,9 @@ void frr_pthread_stop_all(void);
|
|||||||
#define pthread_condattr_setclock(A, B)
|
#define pthread_condattr_setclock(A, B)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int frr_pthread_non_controlled_startup(pthread_t thread, const char *name,
|
||||||
|
const char *os_name);
|
||||||
|
|
||||||
/* mutex auto-lock/unlock */
|
/* mutex auto-lock/unlock */
|
||||||
|
|
||||||
/* variant 1:
|
/* variant 1:
|
||||||
|
36
lib/frrcu.c
36
lib/frrcu.c
@ -149,20 +149,9 @@ static struct rcu_thread *rcu_self(void)
|
|||||||
return (struct rcu_thread *)pthread_getspecific(rcu_thread_key);
|
return (struct rcu_thread *)pthread_getspecific(rcu_thread_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
struct rcu_thread *rcu_thread_new(void *arg)
|
||||||
* thread management (for the non-main thread)
|
|
||||||
*/
|
|
||||||
struct rcu_thread *rcu_thread_prepare(void)
|
|
||||||
{
|
{
|
||||||
struct rcu_thread *rt, *cur;
|
struct rcu_thread *rt, *cur = arg;
|
||||||
|
|
||||||
rcu_assert_read_locked();
|
|
||||||
|
|
||||||
if (!rcu_active)
|
|
||||||
rcu_start();
|
|
||||||
|
|
||||||
cur = rcu_self();
|
|
||||||
assert(cur->depth);
|
|
||||||
|
|
||||||
/* new thread always starts with rcu_read_lock held at depth 1, and
|
/* 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
|
* 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;
|
rt->depth = 1;
|
||||||
|
|
||||||
seqlock_init(&rt->rcu);
|
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);
|
rcu_threads_add_tail(&rcu_threads, rt);
|
||||||
|
|
||||||
return 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)
|
void rcu_thread_start(struct rcu_thread *rt)
|
||||||
{
|
{
|
||||||
pthread_setspecific(rcu_thread_key, rt);
|
pthread_setspecific(rcu_thread_key, rt);
|
||||||
|
@ -40,6 +40,12 @@ extern "C" {
|
|||||||
/* opaque */
|
/* opaque */
|
||||||
struct rcu_thread;
|
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
|
/* called before new thread creation, sets up rcu thread info for new thread
|
||||||
* before it actually exits. This ensures possible RCU references are held
|
* before it actually exits. This ensures possible RCU references are held
|
||||||
* for thread startup.
|
* for thread startup.
|
||||||
|
Loading…
Reference in New Issue
Block a user