[musl] Make tss_t the source of truth, not pthread_key_t

Change-Id: I5272f676e3c9ea045a65841f4126356ffb85d39c
diff --git a/third_party/ulib/musl/musl-rules.mk b/third_party/ulib/musl/musl-rules.mk
index 19ed516..66cbc69 100644
--- a/third_party/ulib/musl/musl-rules.mk
+++ b/third_party/ulib/musl/musl-rules.mk
@@ -80,7 +80,7 @@
     $(LOCAL_DIR)/pthread/pthread_getcpuclockid.c \
     $(LOCAL_DIR)/pthread/pthread_getspecific.c \
     $(LOCAL_DIR)/pthread/pthread_join.c \
-    $(LOCAL_DIR)/pthread/pthread_key_create.c \
+    $(LOCAL_DIR)/pthread/pthread_key.c \
     $(LOCAL_DIR)/pthread/pthread_kill.c \
     $(LOCAL_DIR)/pthread/pthread_mutex_consistent.c \
     $(LOCAL_DIR)/pthread/pthread_mutex_destroy.c \
@@ -821,8 +821,7 @@
     $(LOCAL_DIR)/src/thread/thrd_join.c \
     $(LOCAL_DIR)/src/thread/thrd_sleep.c \
     $(LOCAL_DIR)/src/thread/thrd_yield.c \
-    $(LOCAL_DIR)/src/thread/tss_create.c \
-    $(LOCAL_DIR)/src/thread/tss_delete.c \
+    $(LOCAL_DIR)/src/thread/tss.c \
     $(LOCAL_DIR)/src/thread/tss_set.c \
     $(LOCAL_DIR)/src/time/__asctime.c \
     $(LOCAL_DIR)/src/time/__map_file.c \
diff --git a/third_party/ulib/musl/pthread/pthread_create.c b/third_party/ulib/musl/pthread/pthread_create.c
index 6cc8df5..a9593c9 100644
--- a/third_party/ulib/musl/pthread/pthread_create.c
+++ b/third_party/ulib/musl/pthread/pthread_create.c
@@ -169,7 +169,7 @@
 
     __tls_run_dtors();
 
-    __pthread_tsd_run_dtors();
+    __thread_tsd_run_dtors();
 
     __dl_thread_cleanup();
 
diff --git a/third_party/ulib/musl/pthread/pthread_key.c b/third_party/ulib/musl/pthread/pthread_key.c
new file mode 100644
index 0000000..f9b3f44
--- /dev/null
+++ b/third_party/ulib/musl/pthread/pthread_key.c
@@ -0,0 +1,14 @@
+#include "threads_impl.h"
+
+#include <assert.h>
+
+static_assert(TSS_DTOR_ITERATIONS == PTHREAD_DESTRUCTOR_ITERATIONS, "");
+
+int pthread_key_create(pthread_key_t* k, void (*dtor)(void*)) {
+    return tss_create(k, dtor) == thrd_success ? 0 : EAGAIN;
+}
+
+int pthread_key_delete(pthread_key_t k) {
+    tss_delete(k);
+    return 0;
+}
diff --git a/third_party/ulib/musl/pthread/pthread_key_create.c b/third_party/ulib/musl/pthread/pthread_key_create.c
deleted file mode 100644
index 53e619b..0000000
--- a/third_party/ulib/musl/pthread/pthread_key_create.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "threads_impl.h"
-
-typedef void (*key_t)(void*);
-static _Atomic(key_t) keys[PTHREAD_KEYS_MAX];
-
-static void nodtor(void* dummy) {}
-
-int __pthread_key_create(pthread_key_t* k, void (*dtor)(void*)) {
-    unsigned i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX;
-    unsigned j = i;
-
-    if (!dtor)
-        dtor = nodtor;
-    do {
-        key_t expected = NULL;
-        if (atomic_compare_exchange_strong(&keys[j], &expected, dtor)) {
-            *k = j;
-            return 0;
-        }
-    } while ((j = (j + 1) % PTHREAD_KEYS_MAX) != i);
-    return EAGAIN;
-}
-
-int __pthread_key_delete(pthread_key_t k) {
-    atomic_store(&keys[k], NULL);
-    return 0;
-}
-
-void __pthread_tsd_run_dtors(void) {
-    pthread_t self = __pthread_self();
-    int i, j, not_finished = self->tsd_used;
-    for (j = 0; not_finished && j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
-        not_finished = 0;
-        for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
-            if (self->tsd[i] && atomic_load(&keys[i])) {
-                void* tmp = self->tsd[i];
-                self->tsd[i] = 0;
-                atomic_load(&keys[i])(tmp);
-                not_finished = 1;
-            }
-        }
-    }
-}
-
-weak_alias(__pthread_key_delete, pthread_key_delete);
-weak_alias(__pthread_key_create, pthread_key_create);
diff --git a/third_party/ulib/musl/src/conf/sysconf.c b/third_party/ulib/musl/src/conf/sysconf.c
index 5db672d..b45d234 100644
--- a/third_party/ulib/musl/src/conf/sysconf.c
+++ b/third_party/ulib/musl/src/conf/sysconf.c
@@ -3,6 +3,7 @@
 #include <limits.h>
 #include <signal.h>
 #include <stdint.h>
+#include <threads.h>
 #include <unistd.h>
 
 #include <zircon/syscalls.h>
@@ -80,7 +81,7 @@
             [_SC_GETPW_R_SIZE_MAX] = -1,
             [_SC_LOGIN_NAME_MAX] = 256,
             [_SC_TTY_NAME_MAX] = TTY_NAME_MAX,
-            [_SC_THREAD_DESTRUCTOR_ITERATIONS] = PTHREAD_DESTRUCTOR_ITERATIONS,
+            [_SC_THREAD_DESTRUCTOR_ITERATIONS] = TSS_DTOR_ITERATIONS,
             [_SC_THREAD_KEYS_MAX] = PTHREAD_KEYS_MAX,
             [_SC_THREAD_STACK_MIN] = PTHREAD_STACK_MIN,
             [_SC_THREAD_THREADS_MAX] = -1,
diff --git a/third_party/ulib/musl/src/internal/threads_impl.h b/third_party/ulib/musl/src/internal/threads_impl.h
index 00c7671..f78dbea 100644
--- a/third_party/ulib/musl/src/internal/threads_impl.h
+++ b/third_party/ulib/musl/src/internal/threads_impl.h
@@ -159,9 +159,6 @@
 // Signal n (or all, for -1) threads on a pthread_cond_t or cnd_t.
 void __private_cond_signal(void* condvar, int n) ATTR_LIBC_VISIBILITY;
 
-int __pthread_key_create(tss_t*, void (*)(void*)) ATTR_LIBC_VISIBILITY;
-int __pthread_key_delete(tss_t k) ATTR_LIBC_VISIBILITY;
-
 // This is guaranteed to only return 0, EINVAL, or ETIMEDOUT.
 int __timedwait(atomic_int*, int, clockid_t, const struct timespec*)
     ATTR_LIBC_VISIBILITY;
@@ -174,7 +171,7 @@
 void __thread_allocation_inhibit(void) ATTR_LIBC_VISIBILITY;
 void __thread_allocation_release(void) ATTR_LIBC_VISIBILITY;
 
-void __pthread_tsd_run_dtors(void) ATTR_LIBC_VISIBILITY;
+void __thread_tsd_run_dtors(void) ATTR_LIBC_VISIBILITY;
 
 #define DEFAULT_PTHREAD_ATTR                                                  \
     ((pthread_attr_t){                                                        \
diff --git a/third_party/ulib/musl/src/thread/tss.c b/third_party/ulib/musl/src/thread/tss.c
new file mode 100644
index 0000000..606840b
--- /dev/null
+++ b/third_party/ulib/musl/src/thread/tss.c
@@ -0,0 +1,49 @@
+#include "threads_impl.h"
+
+// C11 does not define any way for applications to know the maximum
+// number of tss_t slots. pthreads, however, does, via the
+// PTHREAD_KEYS_MAX constant. So we allow that bit of pthreads to
+// bleed over here (and into sysconf, which also reports the value)
+// rather than go through some circuituous pattern to define an
+// internal constant that's just the same as the pthread one.
+
+typedef void (*key_t)(void*);
+static _Atomic(key_t) keys[PTHREAD_KEYS_MAX];
+
+static void nodtor(void* dummy) {}
+
+int tss_create(tss_t* k, void (*dtor)(void*)) {
+    unsigned i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX;
+    unsigned j = i;
+
+    if (!dtor)
+        dtor = nodtor;
+    do {
+        key_t expected = NULL;
+        if (atomic_compare_exchange_strong(&keys[j], &expected, dtor)) {
+            *k = j;
+            return 0;
+        }
+    } while ((j = (j + 1) % PTHREAD_KEYS_MAX) != i);
+    return EAGAIN;
+}
+
+void tss_delete(tss_t k) {
+    atomic_store(&keys[k], NULL);
+}
+
+void __thread_tsd_run_dtors(void) {
+    thrd_t self = __thrd_current();
+    int i, j, not_finished = self->tsd_used;
+    for (j = 0; not_finished && j < TSS_DTOR_ITERATIONS; j++) {
+        not_finished = 0;
+        for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
+            if (self->tsd[i] && atomic_load(&keys[i])) {
+                void* tmp = self->tsd[i];
+                self->tsd[i] = 0;
+                atomic_load(&keys[i])(tmp);
+                not_finished = 1;
+            }
+        }
+    }
+}