148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com#include "SkTLS.h"
248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
37b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com// enable to help debug TLS storage
47b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com//#define SK_TRACE_TLS_LIFETIME
57b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com
67b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com
77b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com#ifdef SK_TRACE_TLS_LIFETIME
87b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com    #include "SkThread.h"
97b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com    static int32_t gTLSRecCount;
107b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com#endif
117b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com
1248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.comstruct SkTLSRec {
1348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    SkTLSRec*           fNext;
1448ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    void*               fData;
1548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    SkTLS::CreateProc   fCreateProc;
1648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    SkTLS::DeleteProc   fDeleteProc;
1748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
187b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com#ifdef SK_TRACE_TLS_LIFETIME
197b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com    SkTLSRec() {
207b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com        int n = sk_atomic_inc(&gTLSRecCount);
217b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com        SkDebugf(" SkTLSRec[%d]\n", n);
227b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com    }
237b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com#endif
247b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com
2548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    ~SkTLSRec() {
2648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        if (fDeleteProc) {
2748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            fDeleteProc(fData);
2848ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        }
2948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        // else we leak fData, or it will be managed by the caller
307b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com
317b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com#ifdef SK_TRACE_TLS_LIFETIME
327b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com        int n = sk_atomic_dec(&gTLSRecCount);
337b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com        SkDebugf("~SkTLSRec[%d]\n", n - 1);
347b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com#endif
3548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    }
3648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com};
3748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
3848ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.comvoid SkTLS::Destructor(void* ptr) {
397b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com#ifdef SK_TRACE_TLS_LIFETIME
407b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com    SkDebugf("SkTLS::Destructor(%p)\n", ptr);
417b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com#endif
427b578928a5705f40cfe051ae1c41c1b2e1df0bddreed@google.com
4348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    SkTLSRec* rec = (SkTLSRec*)ptr;
4448ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    do {
4548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        SkTLSRec* next = rec->fNext;
4648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        SkDELETE(rec);
4748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        rec = next;
4849f085dddff10473b6ebf832a974288300224e60bsalomon    } while (rec);
4948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com}
5048ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
5148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.comvoid* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) {
5248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    if (NULL == createProc) {
5348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        return NULL;
5448ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    }
5548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
56331e2dc8eb69b093bf012d8dcd1ab652d67fc36breed@google.com    void* ptr = SkTLS::PlatformGetSpecific(true);
5748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
5848ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    if (ptr) {
5948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        const SkTLSRec* rec = (const SkTLSRec*)ptr;
6048ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        do {
6148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            if (rec->fCreateProc == createProc) {
6248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com                SkASSERT(rec->fDeleteProc == deleteProc);
6348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com                return rec->fData;
6448ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            }
6548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        } while ((rec = rec->fNext) != NULL);
6648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        // not found, so create a new one
6748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    }
68fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
6948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    // add a new head of our change
7048ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    SkTLSRec* rec = new SkTLSRec;
7148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    rec->fNext = (SkTLSRec*)ptr;
7248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
7348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    SkTLS::PlatformSetSpecific(rec);
7448ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
7548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    rec->fData = createProc();
7648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    rec->fCreateProc = createProc;
7748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    rec->fDeleteProc = deleteProc;
7848ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    return rec->fData;
7948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com}
8048ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
8148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.comvoid* SkTLS::Find(CreateProc createProc) {
8248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    if (NULL == createProc) {
8348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        return NULL;
8448ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    }
85fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
86331e2dc8eb69b093bf012d8dcd1ab652d67fc36breed@google.com    void* ptr = SkTLS::PlatformGetSpecific(false);
8748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
8848ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    if (ptr) {
8948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        const SkTLSRec* rec = (const SkTLSRec*)ptr;
9048ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        do {
9148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            if (rec->fCreateProc == createProc) {
9248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com                return rec->fData;
9348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            }
9448ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        } while ((rec = rec->fNext) != NULL);
9548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    }
9648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    return NULL;
9748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com}
9848ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com
9948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.comvoid SkTLS::Delete(CreateProc createProc) {
10048ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    if (NULL == createProc) {
10148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        return;
10248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    }
103fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
104331e2dc8eb69b093bf012d8dcd1ab652d67fc36breed@google.com    void* ptr = SkTLS::PlatformGetSpecific(false);
105fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
10648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    SkTLSRec* curr = (SkTLSRec*)ptr;
10748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    SkTLSRec* prev = NULL;
10848ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    while (curr) {
10948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        SkTLSRec* next = curr->fNext;
11048ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        if (curr->fCreateProc == createProc) {
11148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            if (prev) {
11248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com                prev->fNext = next;
11348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            } else {
11448ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com                // we have a new head of our chain
11548ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com                SkTLS::PlatformSetSpecific(next);
11648ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            }
11748ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            SkDELETE(curr);
11848ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com            break;
11948ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        }
12048ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        prev = curr;
12148ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com        curr = next;
12248ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com    }
12348ca7e37ef684dea5271b8d779c1ccc66b9bf275reed@google.com}
124