impl SkTLS for windows, refactoring to share code with pthread impl

git-svn-id: http://skia.googlecode.com/svn/trunk@3859 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2012-05-07 20:23:27 +00:00
parent 82d447d4f1
commit 48ca7e37ef
6 changed files with 160 additions and 97 deletions

View File

@ -138,6 +138,7 @@
'../src/core/SkStrokerPriv.cpp',
'../src/core/SkStrokerPriv.h',
'../src/core/SkTextFormatParams.h',
'../src/core/SkTLS.cpp',
'../src/core/SkTSearch.cpp',
'../src/core/SkTSort.h',
'../src/core/SkTemplatesPriv.h',

99
src/core/SkTLS.cpp Executable file
View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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)pthread_key_create(&gSkTLSKey, SkTLS::Destructor);
}
void* SkTLS::Get(CreateProc createProc, DeleteProc deleteProc) {
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) {
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;
return pthread_getspecific(gSkTLSKey);
}
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;
}
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);
}

View File

@ -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);
}