master
  1#include "pthread_impl.h"
  2#include "fork_impl.h"
  3
  4volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX;
  5void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 };
  6
  7static void (*keys[PTHREAD_KEYS_MAX])(void *);
  8
  9static pthread_rwlock_t key_lock = PTHREAD_RWLOCK_INITIALIZER;
 10
 11static pthread_key_t next_key;
 12
 13static void nodtor(void *dummy)
 14{
 15}
 16
 17static void dummy_0(void)
 18{
 19}
 20
 21weak_alias(dummy_0, __tl_lock);
 22weak_alias(dummy_0, __tl_unlock);
 23
 24#ifdef __wasilibc_unmodified_upstream // WASI lacks fork
 25void __pthread_key_atfork(int who)
 26{
 27	if (who<0) __pthread_rwlock_rdlock(&key_lock);
 28	else if (!who) __pthread_rwlock_unlock(&key_lock);
 29	else key_lock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER;
 30}
 31#endif
 32
 33int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
 34{
 35	pthread_t self = __pthread_self();
 36
 37	/* This can only happen in the main thread before
 38	 * pthread_create has been called. */
 39	if (!self->tsd) self->tsd = __pthread_tsd_main;
 40
 41	/* Purely a sentinel value since null means slot is free. */
 42	if (!dtor) dtor = nodtor;
 43
 44	__pthread_rwlock_wrlock(&key_lock);
 45	pthread_key_t j = next_key;
 46	do {
 47		if (!keys[j]) {
 48			keys[next_key = *k = j] = dtor;
 49			__pthread_rwlock_unlock(&key_lock);
 50			return 0;
 51		}
 52	} while ((j=(j+1)%PTHREAD_KEYS_MAX) != next_key);
 53
 54	__pthread_rwlock_unlock(&key_lock);
 55	return EAGAIN;
 56}
 57
 58int __pthread_key_delete(pthread_key_t k)
 59{
 60	sigset_t set;
 61	pthread_t self = __pthread_self(), td=self;
 62
 63#ifdef __wasilibc_unmodified_upstream
 64	__block_app_sigs(&set);
 65#endif
 66	__pthread_rwlock_wrlock(&key_lock);
 67
 68	__tl_lock();
 69	do td->tsd[k] = 0;
 70	while ((td=td->next)!=self);
 71	__tl_unlock();
 72
 73	keys[k] = 0;
 74
 75	__pthread_rwlock_unlock(&key_lock);
 76#ifdef __wasilibc_unmodified_upstream
 77	__restore_sigs(&set);
 78#endif
 79
 80	return 0;
 81}
 82
 83void __pthread_tsd_run_dtors()
 84{
 85	pthread_t self = __pthread_self();
 86	int i, j;
 87	for (j=0; self->tsd_used && j<PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
 88		__pthread_rwlock_rdlock(&key_lock);
 89		self->tsd_used = 0;
 90		for (i=0; i<PTHREAD_KEYS_MAX; i++) {
 91			void *val = self->tsd[i];
 92			void (*dtor)(void *) = keys[i];
 93			self->tsd[i] = 0;
 94			if (val && dtor && dtor != nodtor) {
 95				__pthread_rwlock_unlock(&key_lock);
 96				dtor(val);
 97				__pthread_rwlock_rdlock(&key_lock);
 98			}
 99		}
100		__pthread_rwlock_unlock(&key_lock);
101	}
102}
103
104weak_alias(__pthread_key_create, pthread_key_create);
105weak_alias(__pthread_key_delete, pthread_key_delete);