mirror of
git://git.musl-libc.org/musl
synced 2025-03-06 20:48:29 +01:00
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.
99 lines
2.2 KiB
C
99 lines
2.2 KiB
C
#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 };
|
|
|
|
static void (*keys[PTHREAD_KEYS_MAX])(void *);
|
|
|
|
static pthread_rwlock_t key_lock = PTHREAD_RWLOCK_INITIALIZER;
|
|
|
|
static pthread_key_t next_key;
|
|
|
|
static void nodtor(void *dummy)
|
|
{
|
|
}
|
|
|
|
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();
|
|
|
|
/* This can only happen in the main thread before
|
|
* pthread_create has been called. */
|
|
if (!self->tsd) self->tsd = __pthread_tsd_main;
|
|
|
|
/* Purely a sentinel value since null means slot is free. */
|
|
if (!dtor) dtor = nodtor;
|
|
|
|
__pthread_rwlock_wrlock(&key_lock);
|
|
pthread_key_t j = next_key;
|
|
do {
|
|
if (!keys[j]) {
|
|
keys[next_key = *k = j] = dtor;
|
|
__pthread_rwlock_unlock(&key_lock);
|
|
return 0;
|
|
}
|
|
} while ((j=(j+1)%PTHREAD_KEYS_MAX) != next_key);
|
|
|
|
__pthread_rwlock_unlock(&key_lock);
|
|
return EAGAIN;
|
|
}
|
|
|
|
int __pthread_key_delete(pthread_key_t k)
|
|
{
|
|
sigset_t set;
|
|
pthread_t self = __pthread_self(), td=self;
|
|
|
|
__block_app_sigs(&set);
|
|
__pthread_rwlock_wrlock(&key_lock);
|
|
|
|
__tl_lock();
|
|
do td->tsd[k] = 0;
|
|
while ((td=td->next)!=self);
|
|
__tl_unlock();
|
|
|
|
keys[k] = 0;
|
|
|
|
__pthread_rwlock_unlock(&key_lock);
|
|
__restore_sigs(&set);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __pthread_tsd_run_dtors()
|
|
{
|
|
pthread_t self = __pthread_self();
|
|
int i, j;
|
|
for (j=0; self->tsd_used && j<PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
|
|
__pthread_rwlock_rdlock(&key_lock);
|
|
self->tsd_used = 0;
|
|
for (i=0; i<PTHREAD_KEYS_MAX; i++) {
|
|
void *val = self->tsd[i];
|
|
void (*dtor)(void *) = keys[i];
|
|
self->tsd[i] = 0;
|
|
if (val && dtor && dtor != nodtor) {
|
|
__pthread_rwlock_unlock(&key_lock);
|
|
dtor(val);
|
|
__pthread_rwlock_rdlock(&key_lock);
|
|
}
|
|
}
|
|
__pthread_rwlock_unlock(&key_lock);
|
|
}
|
|
}
|
|
|
|
weak_alias(__pthread_key_create, pthread_key_create);
|
|
weak_alias(__pthread_key_delete, pthread_key_delete);
|