aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-04-23 12:51:32 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-04-23 12:51:32 +0000
commite6f7d6821fa3cd836e0af6596d8a15e961ebd2e3 (patch)
tree16cbdde75c8ac2e53656a7c20c39ab002a34ad26 /src
parentfa1755f12c011a474ed6b75d7ae79f127a29b7e8 (diff)
add experimental tls (for font cache eventually)
git-svn-id: http://skia.googlecode.com/svn/trunk@3748 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r--src/core/SkTLS.h36
-rw-r--r--src/ports/SkThread_pthread.cpp80
2 files changed, 116 insertions, 0 deletions
diff --git a/src/core/SkTLS.h b/src/core/SkTLS.h
new file mode 100644
index 0000000000..86886f0080
--- /dev/null
+++ b/src/core/SkTLS.h
@@ -0,0 +1,36 @@
+//
+// SkTLS.h
+//
+//
+// Created by Mike Reed on 4/21/12.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef SkTLS_DEFINED
+#define SkTLS_DEFINED
+
+#include "SkTypes.h"
+
+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
+ * never invoked in Find, it is only used as a key for searching the
+ * cache.
+ */
+ static void* Find(CreateProc);
+};
+
+#endif
diff --git a/src/ports/SkThread_pthread.cpp b/src/ports/SkThread_pthread.cpp
index 4750d4f2c4..87606e2ca7 100644
--- a/src/ports/SkThread_pthread.cpp
+++ b/src/ports/SkThread_pthread.cpp
@@ -149,3 +149,83 @@ void SkMutex::release() {
}
#endif // !SK_USE_POSIX_THREADS
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkTLS.h"
+
+struct SkTLSRec {
+ SkTLSRec* fNext;
+ void* fData;
+ SkTLS::CreateProc fCreateProc;
+ SkTLS::DeleteProc fDeleteProc;
+};
+
+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;
+ 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* SkTLS::Find(CreateProc createProc) {
+ 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) {
+ return rec->fData;
+ }
+ } while ((rec = rec->fNext) != NULL);
+ }
+ return NULL;
+}
+