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