X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=src%2Fthread%2Fpthread_key_create.c;h=d112094122b316d161a6fd17f1c08d12d0b58e05;hb=6aeb9c6703670649ee09b3c8575fb428168bb75c;hp=52c09734b031dfaff67fb38e5332ad22e5978015;hpb=b480808a6a511c9350a6559b63938ac261c83a76;p=musl diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c index 52c09734..d1120941 100644 --- a/src/thread/pthread_key_create.c +++ b/src/thread/pthread_key_create.c @@ -1,26 +1,91 @@ #include "pthread_impl.h" -const size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; +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) { } -int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) +static void dummy_0(void) { - static void (*keys[PTHREAD_KEYS_MAX])(void *); - int i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX; - int j = i; +} + +weak_alias(dummy_0, __tl_lock); +weak_alias(dummy_0, __tl_unlock); - pthread_self(); - libc.tsd_keys = keys; +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; - /* Cheap trick - &k cannot match any destructor pointer */ - while (a_cas_p(keys+j, 0, &k) - && (j=(j+1)%PTHREAD_KEYS_MAX) != i); - if (keys[j] != (void (*)(void *))&k) - return EAGAIN; - keys[j] = dtor; - *k = j; + + __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 && jtsd_used = 0; + for (i=0; itsd[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);