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:
parent
82d447d4f1
commit
48ca7e37ef
@ -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
99
src/core/SkTLS.cpp
Executable 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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user