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