| #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 (NULL != 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; | |
| } | |
| } |