diff --git a/src/core/SkTLS.h b/src/core/SkTLS.h index 86886f0080..7368d72854 100644 --- a/src/core/SkTLS.h +++ b/src/core/SkTLS.h @@ -11,19 +11,14 @@ #include "SkTypes.h" +/** + * Maintains a per-thread cache, using a CreateProc as the key into that cache. + */ class SkTLS { public: typedef void* (*CreateProc)(); typedef void (*DeleteProc)(void*); - - /** - * Create proc is called once per thread, and its return value is cached - * and returned by this call, treating the proc as a key. When this thread - * exists, if DeleteProc is not NULL, it is called and passed the value - * that was returned by CreateProc. - */ - static void* Get(CreateProc, DeleteProc); - + /** * If Get() has previously been called with this CreateProc, then this * returns its cached data, otherwise it returns NULL. The CreateProc is @@ -31,6 +26,24 @@ public: * cache. */ static void* Find(CreateProc); + + /** + * Return the cached data that was returned by the CreateProc. This proc + * is only called the first time Get is called, and there after it is + * cached (per-thread), using the CreateProc as a key to look it up. + * + * When this thread, or Delete is called, the cached data is removed, and + * if a DeleteProc was specified, it is passed the pointer to the cached + * data. + */ + static void* Get(CreateProc, DeleteProc); + + /** + * Remove (optionally calling the DeleteProc if it was specificed in Get) + * the cached data associated with this CreateProc. If no associated cached + * data is found, do nothing. + */ + static void Delete(CreateProc); }; #endif diff --git a/src/ports/SkThread_pthread.cpp b/src/ports/SkThread_pthread.cpp index 87606e2ca7..2936eb0cfc 100644 --- a/src/ports/SkThread_pthread.cpp +++ b/src/ports/SkThread_pthread.cpp @@ -159,16 +159,20 @@ struct SkTLSRec { void* fData; SkTLS::CreateProc fCreateProc; SkTLS::DeleteProc fDeleteProc; + + ~SkTLSRec() { + if (fDeleteProc) { + fDeleteProc(fData); + } + // else we leak fData, or it will be managed by the caller + } }; static void sk_tls_destructor(void* ptr) { SkTLSRec* rec = (SkTLSRec*)ptr; do { SkTLSRec* next = rec->fNext; - if (rec->fDeleteProc) { - rec->fDeleteProc(rec->fData); - } - delete rec; + SkDELETE(rec); rec = next; } while (NULL != rec); } @@ -229,3 +233,30 @@ void* SkTLS::Find(CreateProc createProc) { return NULL; } +void SkTLS::Delete(CreateProc createProc) { + if (NULL == createProc) { + return; + } + + (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key); + void* ptr = pthread_getspecific(gSkTLSKey); + + SkTLSRec* curr = (const SkTLSRec*)ptr; + SkTLSRec* prev = NULL; + while (curr) { + SkTLSRec* next = curr->fNext; + if (rec->fCreateProc == createProc) { + if (prev) { + prev->fNext = next; + } else { + // we have a new head of our chain + (void)pthread_setspecific(gSkTLSKey, next); + } + SkDELETE(curr); + break; + } + prev = curr; + curr = next; + } +} +