aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/core/SkTLS.cpp99
-rw-r--r--src/core/SkTLS.h23
-rw-r--r--src/ports/SkThread_none.cpp11
-rw-r--r--src/ports/SkThread_pthread.cpp102
-rw-r--r--src/ports/SkThread_win.cpp21
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);
+}
+