1 #include "pthread_impl.h"
3 volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX;
4 void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 };
6 static void (*keys[PTHREAD_KEYS_MAX])(void *);
8 static pthread_rwlock_t key_lock = PTHREAD_RWLOCK_INITIALIZER;
10 static pthread_key_t next_key;
12 static void nodtor(void *dummy)
16 static void dirty(void *dummy)
25 static void clean_dirty_tsd_callback(void *p)
27 struct cleanup_args *args = p;
28 pthread_t self = __pthread_self();
30 for (i=0; i<PTHREAD_KEYS_MAX; i++) {
31 if (keys[i] == dirty && self->tsd[i])
34 /* Arbitrary choice to avoid data race. */
35 if (args->caller == self) args->ret = 0;
38 static void dummy2(void (*f)(void *), void *p)
42 weak_alias(dummy2, __pthread_key_delete_synccall);
44 static int clean_dirty_tsd(void)
46 struct cleanup_args args = {
47 .caller = __pthread_self(),
50 __pthread_key_delete_synccall(clean_dirty_tsd_callback, &args);
54 int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
56 pthread_key_t j = next_key;
57 pthread_t self = __pthread_self();
60 /* This can only happen in the main thread before
61 * pthread_create has been called. */
62 if (!self->tsd) self->tsd = __pthread_tsd_main;
64 /* Purely a sentinel value since null means slot is free. */
65 if (!dtor) dtor = nodtor;
67 pthread_rwlock_wrlock(&key_lock);
70 keys[next_key = *k = j] = dtor;
71 pthread_rwlock_unlock(&key_lock);
73 } else if (keys[j] == dirty) {
76 } while ((j=(j+1)%PTHREAD_KEYS_MAX) != next_key);
78 /* It's possible that all slots are in use or __synccall fails. */
79 if (!found_dirty || clean_dirty_tsd()) {
80 pthread_rwlock_unlock(&key_lock);
84 /* If this point is reached there is necessarily a newly-cleaned
85 * slot to allocate to satisfy the caller's request. Find it and
86 * mark any additional previously-dirty slots clean. */
87 for (j=0; j<PTHREAD_KEYS_MAX; j++) {
88 if (keys[j] == dirty) {
90 keys[next_key = *k = j] = dtor;
98 pthread_rwlock_unlock(&key_lock);
102 int __pthread_key_delete_impl(pthread_key_t k)
104 pthread_rwlock_wrlock(&key_lock);
106 pthread_rwlock_unlock(&key_lock);
110 void __pthread_tsd_run_dtors()
112 pthread_t self = __pthread_self();
114 for (j=0; self->tsd_used && j<PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
115 pthread_rwlock_rdlock(&key_lock);
117 for (i=0; i<PTHREAD_KEYS_MAX; i++) {
118 void *val = self->tsd[i];
119 void (*dtor)(void *) = keys[i];
121 if (val && dtor && dtor != nodtor && dtor != dirty) {
122 pthread_rwlock_unlock(&key_lock);
124 pthread_rwlock_rdlock(&key_lock);
127 pthread_rwlock_unlock(&key_lock);
131 weak_alias(__pthread_key_create, pthread_key_create);