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 
12 struct SkTLSRec {
13     SkTLSRec*           fNext;
14     void*               fData;
15     SkTLS::CreateProc   fCreateProc;
16     SkTLS::DeleteProc   fDeleteProc;
17 
18 #ifdef SK_TRACE_TLS_LIFETIME
SkTLSRecSkTLSRec19     SkTLSRec() {
20         int n = sk_atomic_inc(&gTLSRecCount);
21         SkDebugf(" SkTLSRec[%d]\n", n);
22     }
23 #endif
24 
~SkTLSRecSkTLSRec25     ~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 
Destructor(void * ptr)38 void 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 
Get(CreateProc createProc,DeleteProc deleteProc)51 void* 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 
Find(CreateProc createProc)81 void* 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 
Delete(CreateProc createProc)99 void 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