#include "SkTLS.h" // enable to help debug TLS storage //#define SK_TRACE_TLS_LIFETIME #ifdef SK_TRACE_TLS_LIFETIME #include "SkThread.h" static int32_t gTLSRecCount; #endif struct SkTLSRec { SkTLSRec* fNext; void* fData; SkTLS::CreateProc fCreateProc; SkTLS::DeleteProc fDeleteProc; #ifdef SK_TRACE_TLS_LIFETIME SkTLSRec() { int n = sk_atomic_inc(&gTLSRecCount); SkDebugf(" SkTLSRec[%d]\n", n); } #endif ~SkTLSRec() { if (fDeleteProc) { fDeleteProc(fData); } // else we leak fData, or it will be managed by the caller #ifdef SK_TRACE_TLS_LIFETIME int n = sk_atomic_dec(&gTLSRecCount); SkDebugf("~SkTLSRec[%d]\n", n - 1); #endif } }; void SkTLS::Destructor(void* ptr) { #ifdef SK_TRACE_TLS_LIFETIME SkDebugf("SkTLS::Destructor(%p)\n", ptr); #endif SkTLSRec* rec = (SkTLSRec*)ptr; do { SkTLSRec* next = rec->fNext; SkDELETE(rec); rec = next; } while (rec); } void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) { if (NULL == createProc) { return NULL; } void* ptr = SkTLS::PlatformGetSpecific(true); if (ptr) { const SkTLSRec* rec = (const SkTLSRec*)ptr; do { if (rec->fCreateProc == createProc) { SkASSERT(rec->fDeleteProc == deleteProc); return rec->fData; } } while ((rec = rec->fNext) != NULL); // not found, so create a new one } // add a new head of our change SkTLSRec* rec = new SkTLSRec; rec->fNext = (SkTLSRec*)ptr; SkTLS::PlatformSetSpecific(rec); rec->fData = createProc(); rec->fCreateProc = createProc; rec->fDeleteProc = deleteProc; return rec->fData; } void* SkTLS::Find(CreateProc createProc) { if (NULL == createProc) { return NULL; } void* ptr = SkTLS::PlatformGetSpecific(false); if (ptr) { const SkTLSRec* rec = (const SkTLSRec*)ptr; do { if (rec->fCreateProc == createProc) { return rec->fData; } } while ((rec = rec->fNext) != NULL); } return NULL; } void SkTLS::Delete(CreateProc createProc) { if (NULL == createProc) { return; } void* ptr = SkTLS::PlatformGetSpecific(false); SkTLSRec* curr = (SkTLSRec*)ptr; SkTLSRec* prev = NULL; while (curr) { SkTLSRec* next = curr->fNext; if (curr->fCreateProc == createProc) { if (prev) { prev->fNext = next; } else { // we have a new head of our chain SkTLS::PlatformSetSpecific(next); } SkDELETE(curr); break; } prev = curr; curr = next; } }