| 1 | #include "pthread_impl.h" |
| 2 | #include "fork_impl.h" |
| 3 | |
| 4 | volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; |
| 5 | void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 }; |
| 6 | |
| 7 | static void (*keys[PTHREAD_KEYS_MAX])(void *); |
| 8 | |
| 9 | static pthread_rwlock_t key_lock = PTHREAD_RWLOCK_INITIALIZER; |
| 10 | |
| 11 | static pthread_key_t next_key; |
| 12 | |
| 13 | static void nodtor(void *dummy) |
| 14 | { |
| 15 | } |
| 16 | |
| 17 | static void dummy_0(void) |
| 18 | { |
| 19 | } |
| 20 | |
| 21 | weak_alias(dummy_0, __tl_lock); |
| 22 | weak_alias(dummy_0, __tl_unlock); |
| 23 | |
| 24 | #ifdef __wasilibc_unmodified_upstream // WASI lacks fork |
| 25 | void __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 | |
| 33 | int __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 | |
| 58 | int __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 | |
| 83 | void __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 | |
| 104 | weak_alias(__pthread_key_create, pthread_key_create); |
| 105 | weak_alias(__pthread_key_delete, pthread_key_delete); |