1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
| | #include "pthread_impl.h"
#include <threads.h>
/* 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<TSS_DTOR_ITERATIONS; j++) {
for (unsigned i=0; i<tss_max; i++) {
if (data[i]) {
void *tmp = data[i];
data[i] = 0;
--used;
// slot i might have been deleted, check
if (dtors[i]) dtors[i](tmp);
if (!used) return;
}
}
}
}
|