fix missing synchronization of pthread TSD keys with MT-fork

commit 167390f055 seems to have
overlooked the presence of a lock here, probably because it was one of
the exceptions not using LOCK() but a rwlock.

as such, it can't be added to the generic table of locks to take, so
add an explicit atfork function for the pthread keys table. the order
it is called does not particularly matter since nothing else in libc
but pthread_exit interacts with keys.
This commit is contained in:
Rich Felker 2022-10-07 21:36:25 -04:00
parent 5ff3eea91f
commit cf76df0e1f
3 changed files with 12 additions and 0 deletions

View file

@ -16,3 +16,4 @@ extern hidden volatile int *const __vmlock_lockptr;
hidden void __malloc_atfork(int);
hidden void __ldso_atfork(int);
hidden void __pthread_key_atfork(int);

View file

@ -37,6 +37,7 @@ static void dummy(int x) { }
weak_alias(dummy, __fork_handler);
weak_alias(dummy, __malloc_atfork);
weak_alias(dummy, __aio_atfork);
weak_alias(dummy, __pthread_key_atfork);
weak_alias(dummy, __ldso_atfork);
static void dummy_0(void) { }
@ -51,6 +52,7 @@ pid_t fork(void)
int need_locks = libc.need_locks > 0;
if (need_locks) {
__ldso_atfork(-1);
__pthread_key_atfork(-1);
__aio_atfork(-1);
__inhibit_ptc();
for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
@ -78,6 +80,7 @@ pid_t fork(void)
else **atfork_locks[i] = 0;
__release_ptc();
if (ret) __aio_atfork(0);
__pthread_key_atfork(!ret);
__ldso_atfork(!ret);
}
__restore_sigs(&set);

View file

@ -1,4 +1,5 @@
#include "pthread_impl.h"
#include "fork_impl.h"
volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX;
void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 };
@ -20,6 +21,13 @@ static void dummy_0(void)
weak_alias(dummy_0, __tl_lock);
weak_alias(dummy_0, __tl_unlock);
void __pthread_key_atfork(int who)
{
if (who<0) __pthread_rwlock_rdlock(&key_lock);
else if (!who) __pthread_rwlock_unlock(&key_lock);
else key_lock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER;
}
int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
{
pthread_t self = __pthread_self();