diff options
author | Rich Felker <dalias@aerifal.cx> | 2022-10-07 21:36:25 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2022-10-19 14:01:32 -0400 |
commit | cf76df0e1fe09b0d504ca650fdaa01df5bf9ab72 (patch) | |
tree | 6a3841d780547892c723d11221aaea3e5fa3f85c | |
parent | 5ff3eea91fa6bdce25b3a35644433f68e076beca (diff) | |
download | musl-cf76df0e1fe09b0d504ca650fdaa01df5bf9ab72.tar.gz musl-cf76df0e1fe09b0d504ca650fdaa01df5bf9ab72.tar.xz musl-cf76df0e1fe09b0d504ca650fdaa01df5bf9ab72.zip |
fix missing synchronization of pthread TSD keys with MT-fork
commit 167390f05564e0a4d3fcb4329377fd7743267560 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.
-rw-r--r-- | src/internal/fork_impl.h | 1 | ||||
-rw-r--r-- | src/process/fork.c | 3 | ||||
-rw-r--r-- | src/thread/pthread_key_create.c | 8 |
3 files changed, 12 insertions, 0 deletions
diff --git a/src/internal/fork_impl.h b/src/internal/fork_impl.h index ae3a79e5..354e733b 100644 --- a/src/internal/fork_impl.h +++ b/src/internal/fork_impl.h @@ -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); diff --git a/src/process/fork.c b/src/process/fork.c index 80e804b1..56f19313 100644 --- a/src/process/fork.c +++ b/src/process/fork.c @@ -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); diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c index d1120941..39770c7a 100644 --- a/src/thread/pthread_key_create.c +++ b/src/thread/pthread_key_create.c @@ -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(); |