mirror of
https://git.musl-libc.org/git/musl
synced 2025-02-22 13:14:39 +03:00
rewrite pthread_key_delete to use global thread list
with the availability of the thread list, there is no need to mark tsd key slots dirty and clean them up only when a free slot can't be found. instead, directly iterate threads and clear any value associated with the key being deleted. no synchronization is necessary for the clearing, since there is no way the slot can be accessed without having synchronized with the creation of a new key occupying the same slot, which is already sequenced after and synchronized with the deletion of the old key.
This commit is contained in:
parent
e4235d7067
commit
ba74a42cee
@ -13,49 +13,17 @@ static void nodtor(void *dummy)
|
||||
{
|
||||
}
|
||||
|
||||
static void dirty(void *dummy)
|
||||
static void dummy_0(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct cleanup_args {
|
||||
pthread_t caller;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void clean_dirty_tsd_callback(void *p)
|
||||
{
|
||||
struct cleanup_args *args = p;
|
||||
pthread_t self = __pthread_self();
|
||||
pthread_key_t i;
|
||||
for (i=0; i<PTHREAD_KEYS_MAX; i++) {
|
||||
if (keys[i] == dirty && self->tsd[i])
|
||||
self->tsd[i] = 0;
|
||||
}
|
||||
/* Arbitrary choice to avoid data race. */
|
||||
if (args->caller == self) args->ret = 0;
|
||||
}
|
||||
|
||||
static void dummy2(void (*f)(void *), void *p)
|
||||
{
|
||||
}
|
||||
|
||||
weak_alias(dummy2, __pthread_key_delete_synccall);
|
||||
|
||||
static int clean_dirty_tsd(void)
|
||||
{
|
||||
struct cleanup_args args = {
|
||||
.caller = __pthread_self(),
|
||||
.ret = EAGAIN
|
||||
};
|
||||
__pthread_key_delete_synccall(clean_dirty_tsd_callback, &args);
|
||||
return args.ret;
|
||||
}
|
||||
weak_alias(dummy_0, __tl_lock);
|
||||
weak_alias(dummy_0, __tl_unlock);
|
||||
|
||||
int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
|
||||
{
|
||||
pthread_key_t j = next_key;
|
||||
pthread_t self = __pthread_self();
|
||||
int found_dirty = 0;
|
||||
|
||||
/* This can only happen in the main thread before
|
||||
* pthread_create has been called. */
|
||||
@ -70,40 +38,29 @@ int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
|
||||
keys[next_key = *k = j] = dtor;
|
||||
pthread_rwlock_unlock(&key_lock);
|
||||
return 0;
|
||||
} else if (keys[j] == dirty) {
|
||||
found_dirty = 1;
|
||||
}
|
||||
} while ((j=(j+1)%PTHREAD_KEYS_MAX) != next_key);
|
||||
|
||||
/* It's possible that all slots are in use or __synccall fails. */
|
||||
if (!found_dirty || clean_dirty_tsd()) {
|
||||
pthread_rwlock_unlock(&key_lock);
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
/* If this point is reached there is necessarily a newly-cleaned
|
||||
* slot to allocate to satisfy the caller's request. Find it and
|
||||
* mark any additional previously-dirty slots clean. */
|
||||
for (j=0; j<PTHREAD_KEYS_MAX; j++) {
|
||||
if (keys[j] == dirty) {
|
||||
if (dtor) {
|
||||
keys[next_key = *k = j] = dtor;
|
||||
dtor = 0;
|
||||
} else {
|
||||
keys[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_rwlock_unlock(&key_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __pthread_key_delete_impl(pthread_key_t k)
|
||||
int __pthread_key_delete(pthread_key_t k)
|
||||
{
|
||||
sigset_t set;
|
||||
pthread_t self = __pthread_self(), td=self;
|
||||
|
||||
__block_app_sigs(&set);
|
||||
__tl_lock();
|
||||
do td->tsd[k] = 0;
|
||||
while ((td=td->next)!=self);
|
||||
__tl_unlock();
|
||||
__restore_sigs(&set);
|
||||
|
||||
pthread_rwlock_wrlock(&key_lock);
|
||||
keys[k] = dirty;
|
||||
keys[k] = 0;
|
||||
pthread_rwlock_unlock(&key_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -118,7 +75,7 @@ void __pthread_tsd_run_dtors()
|
||||
void *val = self->tsd[i];
|
||||
void (*dtor)(void *) = keys[i];
|
||||
self->tsd[i] = 0;
|
||||
if (val && dtor && dtor != nodtor && dtor != dirty) {
|
||||
if (val && dtor && dtor != nodtor) {
|
||||
pthread_rwlock_unlock(&key_lock);
|
||||
dtor(val);
|
||||
pthread_rwlock_rdlock(&key_lock);
|
||||
@ -129,3 +86,4 @@ void __pthread_tsd_run_dtors()
|
||||
}
|
||||
|
||||
weak_alias(__pthread_key_create, pthread_key_create);
|
||||
weak_alias(__pthread_key_delete, pthread_key_delete);
|
||||
|
@ -1,14 +0,0 @@
|
||||
#include "pthread_impl.h"
|
||||
#include "libc.h"
|
||||
|
||||
void __pthread_key_delete_synccall(void (*f)(void *), void *p)
|
||||
{
|
||||
__synccall(f, p);
|
||||
}
|
||||
|
||||
int __pthread_key_delete(pthread_key_t k)
|
||||
{
|
||||
return __pthread_key_delete_impl(k);
|
||||
}
|
||||
|
||||
weak_alias(__pthread_key_delete, pthread_key_delete);
|
Loading…
x
Reference in New Issue
Block a user