Merge pull request #15714 from mjstapp/sync_pthread_startup

lib: serialize pthread startup
This commit is contained in:
Donald Sharp 2024-04-23 12:55:27 -04:00 committed by GitHub
commit b8f0be9ddd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 46 additions and 0 deletions

View File

@ -92,9 +92,14 @@ struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr,
MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t));
fpt->running_cond = XCALLOC(MTYPE_PTHREAD_PRIM,
sizeof(pthread_cond_t));
pthread_mutex_init(fpt->running_cond_mtx, NULL);
pthread_cond_init(fpt->running_cond, NULL);
pthread_mutex_init(&fpt->startup_cond_mtx, NULL);
pthread_cond_init(&fpt->startup_cond, NULL);
fpt->started = false;
frr_with_mutex (&frr_pthread_list_mtx) {
listnode_add(frr_pthread_list, fpt);
}
@ -108,6 +113,8 @@ static void frr_pthread_destroy_nolock(struct frr_pthread *fpt)
pthread_mutex_destroy(&fpt->mtx);
pthread_mutex_destroy(fpt->running_cond_mtx);
pthread_cond_destroy(fpt->running_cond);
pthread_mutex_destroy(&fpt->startup_cond_mtx);
pthread_cond_destroy(&fpt->startup_cond);
XFREE(MTYPE_FRR_PTHREAD, fpt->name);
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx);
XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond);
@ -140,11 +147,34 @@ int frr_pthread_set_name(struct frr_pthread *fpt)
return ret;
}
/* New pthread waits before running */
static void frr_pthread_wait_startup(struct frr_pthread *fpt)
{
frr_with_mutex (&fpt->startup_cond_mtx) {
while (!fpt->started)
pthread_cond_wait(&fpt->startup_cond,
&fpt->startup_cond_mtx);
}
}
/* Parent pthread allows new pthread to start running */
static void frr_pthread_notify_startup(struct frr_pthread *fpt)
{
frr_with_mutex (&fpt->startup_cond_mtx) {
fpt->started = true;
pthread_cond_signal(&fpt->startup_cond);
}
}
static void *frr_pthread_inner(void *arg)
{
struct frr_pthread *fpt = arg;
/* The new pthead waits until the parent allows it to continue. */
frr_pthread_wait_startup(fpt);
rcu_thread_start(fpt->rcu_thread);
return fpt->attr.start(fpt);
}
@ -169,6 +199,9 @@ int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
/* Restore caller's signals */
pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
/* Allow new child pthread to start */
frr_pthread_notify_startup(fpt);
/*
* Per pthread_create(3), the contents of fpt->thread are undefined if
* pthread_create() did not succeed. Reset this value to zero.
@ -250,6 +283,8 @@ int frr_pthread_non_controlled_startup(pthread_t thread, const char *name,
fpt->thread = thread;
fpt->rcu_thread = rcu_thread;
fpt->started = true;
frr_pthread_inner(fpt);
return 0;

View File

@ -46,6 +46,17 @@ struct frr_pthread {
/* caller-specified data; start & stop funcs, name, id */
struct frr_pthread_attr attr;
/*
* Startup serialization: newly-started pthreads wait at a point
* very early in life so that there isn't a race with the
* starting pthread. The OS 'start' apis don't make any guarantees
* about which pthread runs first - the existing pthread that has
* called the 'start' api, or the new pthread that is just starting.
*/
pthread_cond_t startup_cond;
pthread_mutex_t startup_cond_mtx;
atomic_bool started;
/*
* Notification mechanism for allowing pthreads to notify their parents
* when they are ready to do work. This mechanism has two associated