#include "pthread_impl.h" #include /* future version of C might prescribe a minimum number of tss */ #define __TSS_MAX_MIN 64 #ifndef TSS_MAX # define TSS_MAX __TSS_MAX_MIN #endif #define __LOW_BIT(X) ((X+0U) & -(X+0U)) #define STRINGIFY_(X) #X #define STRINGIFY(X) STRINGIFY_(X) #define WARN__(X) _Pragma(#X) #define WARN_(X) WARN__(message (X)) #define WARN(X) WARN_(X) #if (TSS_MAX) < __TSS_MAX_MIN WARN("TSS_MAX " STRINGIFY(TSS_MAX) " replaced by minimal value " STRINGIFY(__TSS_MAX_MIN)) # undef TSS_MAX # define TSS_MAX __TSS_MAX_MIN #endif #if (TSS_MAX) != __LOW_BIT(TSS_MAX) # error TSS_MAX must be a power of 2 #endif enum { tss_max = (TSS_MAX), }; static tss_dtor_t dtors[tss_max]; static void nodtor(void *dummy) { } /* This should use _Thread_local which must exist for C11 threads. Since musl might get compiled with pre-C11 options we use gcc's __thread extension, instead. */ static __thread void * data[tss_max]; /* Thread local data is accounted for with a usage counter */ static __thread tss_t used; int tss_create(tss_t *tss, tss_dtor_t dtor) { unsigned start = (uintptr_t)&tss / 16 % tss_max; if (!dtor) dtor = nodtor; for (unsigned i = 0; i < tss_max; ++i) { unsigned j = (start+i)%tss_max; if (!a_cas_p(dtors+j, 0, (void *)dtor)) { *tss = j; return thrd_success; } } *tss = -1; return thrd_error; } void tss_delete(tss_t k) { /* tss_delete has no failure path, so check the argument. */ if (k < tss_max) dtors[k] = 0; } int tss_set(tss_t k, void *x) { if (k >= tss_max || !dtors[k]) return thrd_error; if (data[k] != x) { /* tss_set can be used to add or remove a tss. compute the difference in usage. */ used += (!!x - !!data[k]); data[k] = x; } return thrd_success; } void * tss_get(tss_t k) { return dtors[k] ? data[k] : 0; } void __tss_run_dtors(void) { for (unsigned j=0; used && j