diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/core/SkTLS.cpp | 99 | ||||
-rw-r--r-- | src/core/SkTLS.h | 23 | ||||
-rw-r--r-- | src/ports/SkThread_none.cpp | 11 | ||||
-rw-r--r-- | src/ports/SkThread_pthread.cpp | 102 | ||||
-rw-r--r-- | src/ports/SkThread_win.cpp | 21 |
5 files changed, 159 insertions, 97 deletions
diff --git a/src/core/SkTLS.cpp b/src/core/SkTLS.cpp new file mode 100755 index 0000000000..0cd79de9ff --- /dev/null +++ b/src/core/SkTLS.cpp @@ -0,0 +1,99 @@ +#include "SkTLS.h" + +struct SkTLSRec { + SkTLSRec* fNext; + 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 + } +}; + +void SkTLS::Destructor(void* ptr) { + 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(); + + 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(); + + 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(); + + 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; + } +} + diff --git a/src/core/SkTLS.h b/src/core/SkTLS.h index 7368d72854..0ce39247aa 100644 --- a/src/core/SkTLS.h +++ b/src/core/SkTLS.h @@ -44,6 +44,29 @@ public: * data is found, do nothing. */ static void Delete(CreateProc); + +private: + // Our implementation requires only 1 TLS slot, as we manage multiple values + // ourselves in a list, with the platform specific value as our head. + + /** + * implemented by the platform, to return the value of our (one) slot per-thread + */ + static void* PlatformGetSpecific(); + + /** + * implemented by the platform, to set the value for our (one) slot per-thread + */ + static void PlatformSetSpecific(void*); + +public: + /** + * Will delete our internal list. To be called by the platform if/when its + * TLS slot is deleted (often at thread shutdown). + * + * Public *only* for the platform's use, not to be called by a client. + */ + static void Destructor(void* ptr); }; #endif diff --git a/src/ports/SkThread_none.cpp b/src/ports/SkThread_none.cpp index 8361021059..8341d0bfe5 100644 --- a/src/ports/SkThread_none.cpp +++ b/src/ports/SkThread_none.cpp @@ -29,3 +29,14 @@ void SkMutex::acquire() {} void SkMutex::release() {} +////////////////////////////////////////////////////////////////////////// + +static void* gSpecific; + +void* SkTLS::PlatformGetSpecific() { + return gSpecific; +} + +void SkTLS::PlatformSetSpecific(void* ptr) { + gSpecific = ptr; +} diff --git a/src/ports/SkThread_pthread.cpp b/src/ports/SkThread_pthread.cpp index c743d6ea82..b724c5126b 100644 --- a/src/ports/SkThread_pthread.cpp +++ b/src/ports/SkThread_pthread.cpp @@ -152,111 +152,19 @@ void SkMutex::release() { /////////////////////////////////////////////////////////////////////////////// -#include "SkTLS.h" - -struct SkTLSRec { - SkTLSRec* fNext; - 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; - SkDELETE(rec); - rec = next; - } while (NULL != rec); -} - static pthread_key_t gSkTLSKey; static pthread_once_t gSkTLSKey_Once = PTHREAD_ONCE_INIT; static void sk_tls_make_key() { - (void)pthread_key_create(&gSkTLSKey, sk_tls_destructor); -} - -void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) { - if (NULL == createProc) { - return NULL; - } - - (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key); - void* ptr = pthread_getspecific(gSkTLSKey); - - 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; - (void)pthread_setspecific(gSkTLSKey, rec); - - rec->fData = createProc(); - rec->fCreateProc = createProc; - rec->fDeleteProc = deleteProc; - return rec->fData; + (void)pthread_key_create(&gSkTLSKey, SkTLS::Destructor); } -void* SkTLS::Find(CreateProc createProc) { - if (NULL == createProc) { - return NULL; - } - +void* SkTLS::PlatformGetSpecific() { (void)pthread_once(&gSkTLSKey_Once, sk_tls_make_key); - void* ptr = pthread_getspecific(gSkTLSKey); - - if (ptr) { - const SkTLSRec* rec = (const SkTLSRec*)ptr; - do { - if (rec->fCreateProc == createProc) { - return rec->fData; - } - } while ((rec = rec->fNext) != NULL); - } - return NULL; + return pthread_getspecific(gSkTLSKey); } -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 = (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 - (void)pthread_setspecific(gSkTLSKey, next); - } - SkDELETE(curr); - break; - } - prev = curr; - curr = next; - } +void SkTLS::PlatformSetSpecific(void* ptr) { + (void)pthread_setspecific(gSkTLSKey, ptr); } diff --git a/src/ports/SkThread_win.cpp b/src/ports/SkThread_win.cpp index 70b8e11122..0d9ecab4bd 100644 --- a/src/ports/SkThread_win.cpp +++ b/src/ports/SkThread_win.cpp @@ -10,6 +10,7 @@ #include <windows.h> #include <intrin.h> #include "SkThread.h" +#include "SkTLS.h" //MSDN says in order to declare an interlocked function for use as an //intrinsic, include intrin.h and put the function in a #pragma intrinsic @@ -44,3 +45,23 @@ void SkMutex::release() { LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage)); } +/////////////////////////////////////////////////////////////////////////// + +static bool gOnce; +static DWORD gTlsIndex; +SK_DECLARE_STATIC_MUTEX(gMutex); + +void* SkTLS::PlatformGetSpecific() { + if (!gOnce) { + SkAutoMutexAcquire tmp(gMutex); + gTlsIndex = TlsAlloc(); + gOnce = true; + } + return TlsGetValue(gTlsIndex); +} + +void SkTLS::PlatformSetSpecific(void* ptr) { + SkASSERT(gOnce); + (void)TlsSetValue(gTlsIndex, ptr); +} + |