1#include "SkTLS.h"
2
3// enable to help debug TLS storage
4//#define SK_TRACE_TLS_LIFETIME
5
6
7#ifdef SK_TRACE_TLS_LIFETIME
8    #include "SkThread.h"
9    static int32_t gTLSRecCount;
10#endif
11
12struct SkTLSRec {
13    SkTLSRec*           fNext;
14    void*               fData;
15    SkTLS::CreateProc   fCreateProc;
16    SkTLS::DeleteProc   fDeleteProc;
17
18#ifdef SK_TRACE_TLS_LIFETIME
19    SkTLSRec() {
20        int n = sk_atomic_inc(&gTLSRecCount);
21        SkDebugf(" SkTLSRec[%d]\n", n);
22    }
23#endif
24
25    ~SkTLSRec() {
26        if (fDeleteProc) {
27            fDeleteProc(fData);
28        }
29        // else we leak fData, or it will be managed by the caller
30
31#ifdef SK_TRACE_TLS_LIFETIME
32        int n = sk_atomic_dec(&gTLSRecCount);
33        SkDebugf("~SkTLSRec[%d]\n", n - 1);
34#endif
35    }
36};
37
38void SkTLS::Destructor(void* ptr) {
39#ifdef SK_TRACE_TLS_LIFETIME
40    SkDebugf("SkTLS::Destructor(%p)\n", ptr);
41#endif
42
43    SkTLSRec* rec = (SkTLSRec*)ptr;
44    do {
45        SkTLSRec* next = rec->fNext;
46        SkDELETE(rec);
47        rec = next;
48    } while (rec);
49}
50
51void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) {
52    if (NULL == createProc) {
53        return NULL;
54    }
55
56    void* ptr = SkTLS::PlatformGetSpecific(true);
57
58    if (ptr) {
59        const SkTLSRec* rec = (const SkTLSRec*)ptr;
60        do {
61            if (rec->fCreateProc == createProc) {
62                SkASSERT(rec->fDeleteProc == deleteProc);
63                return rec->fData;
64            }
65        } while ((rec = rec->fNext) != NULL);
66        // not found, so create a new one
67    }
68
69    // add a new head of our change
70    SkTLSRec* rec = new SkTLSRec;
71    rec->fNext = (SkTLSRec*)ptr;
72
73    SkTLS::PlatformSetSpecific(rec);
74
75    rec->fData = createProc();
76    rec->fCreateProc = createProc;
77    rec->fDeleteProc = deleteProc;
78    return rec->fData;
79}
80
81void* SkTLS::Find(CreateProc createProc) {
82    if (NULL == createProc) {
83        return NULL;
84    }
85
86    void* ptr = SkTLS::PlatformGetSpecific(false);
87
88    if (ptr) {
89        const SkTLSRec* rec = (const SkTLSRec*)ptr;
90        do {
91            if (rec->fCreateProc == createProc) {
92                return rec->fData;
93            }
94        } while ((rec = rec->fNext) != NULL);
95    }
96    return NULL;
97}
98
99void SkTLS::Delete(CreateProc createProc) {
100    if (NULL == createProc) {
101        return;
102    }
103
104    void* ptr = SkTLS::PlatformGetSpecific(false);
105
106    SkTLSRec* curr = (SkTLSRec*)ptr;
107    SkTLSRec* prev = NULL;
108    while (curr) {
109        SkTLSRec* next = curr->fNext;
110        if (curr->fCreateProc == createProc) {
111            if (prev) {
112                prev->fNext = next;
113            } else {
114                // we have a new head of our chain
115                SkTLS::PlatformSetSpecific(next);
116            }
117            SkDELETE(curr);
118            break;
119        }
120        prev = curr;
121        curr = next;
122    }
123}
124