Emulate pthread TLS functions in Windows

This commit is contained in:
Chris Robinson 2011-08-28 17:21:01 -07:00
parent 82244f298c
commit 5eceb593e9
3 changed files with 78 additions and 38 deletions

View File

@ -367,7 +367,7 @@ static ALCcontext *g_pContextList = NULL;
static ALCuint g_ulContextCount = 0; static ALCuint g_ulContextCount = 0;
// Thread-local current context // Thread-local current context
static tls_type LocalContext; static pthread_key_t LocalContext;
// Process-wide current context // Process-wide current context
static ALCcontext *GlobalContext; static ALCcontext *GlobalContext;
@ -421,21 +421,37 @@ static void alc_deinit(void);
static void alc_deinit_safe(void); static void alc_deinit_safe(void);
#ifndef AL_LIBTYPE_STATIC #ifndef AL_LIBTYPE_STATIC
UIntMap TlsDestructor;
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{ {
ALsizei i;
(void)hModule;
// Perform actions based on the reason for calling. // Perform actions based on the reason for calling.
switch(ul_reason_for_call) switch(ul_reason_for_call)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule); InitUIntMap(&TlsDestructor);
alc_init(); alc_init();
break; break;
case DLL_THREAD_DETACH:
for(i = 0;i < TlsDestructor.size;i++)
{
void *ptr = pthread_getspecific(TlsDestructor.array[i].key);
void (*callback)(void*) = (void(*)(void*))TlsDestructor.array[i].value;
if(ptr && callback)
callback(ptr);
}
break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
if(!lpReserved) if(!lpReserved)
alc_deinit(); alc_deinit();
else else
alc_deinit_safe(); alc_deinit_safe();
ResetUIntMap(&TlsDestructor);
break; break;
} }
return TRUE; return TRUE;
@ -483,7 +499,7 @@ static void alc_init(void)
if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1))
ZScale = -1.0; ZScale = -1.0;
tls_create(&LocalContext); pthread_key_create(&LocalContext, NULL);
InitializeCriticalSection(&ListLock); InitializeCriticalSection(&ListLock);
ThunkInit(); ThunkInit();
} }
@ -496,7 +512,7 @@ static void alc_deinit_safe(void)
ThunkExit(); ThunkExit();
DeleteCriticalSection(&ListLock); DeleteCriticalSection(&ListLock);
tls_delete(LocalContext); pthread_key_delete(LocalContext);
if(LogFile != stderr) if(LogFile != stderr)
fclose(LogFile); fclose(LogFile);
@ -1295,10 +1311,10 @@ ALCcontext *GetLockedContext(void)
LockLists(); LockLists();
pContext = tls_get(LocalContext); pContext = pthread_getspecific(LocalContext);
if(pContext && !IsContext(pContext)) if(pContext && !IsContext(pContext))
{ {
tls_set(LocalContext, NULL); pthread_setspecific(LocalContext, NULL);
pContext = NULL; pContext = NULL;
} }
if(!pContext) if(!pContext)
@ -2125,10 +2141,10 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(ALCvoid)
ALCcontext *Context; ALCcontext *Context;
LockLists(); LockLists();
Context = tls_get(LocalContext); Context = pthread_getspecific(LocalContext);
if(Context && !IsContext(Context)) if(Context && !IsContext(Context))
{ {
tls_set(LocalContext, NULL); pthread_setspecific(LocalContext, NULL);
Context = NULL; Context = NULL;
} }
if(!Context) if(!Context)
@ -2149,10 +2165,10 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
LockLists(); LockLists();
pContext = tls_get(LocalContext); pContext = pthread_getspecific(LocalContext);
if(pContext && !IsContext(pContext)) if(pContext && !IsContext(pContext))
{ {
tls_set(LocalContext, NULL); pthread_setspecific(LocalContext, NULL);
pContext = NULL; pContext = NULL;
} }
@ -2197,7 +2213,7 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
if(context == NULL || IsContext(context)) if(context == NULL || IsContext(context))
{ {
GlobalContext = context; GlobalContext = context;
tls_set(LocalContext, NULL); pthread_setspecific(LocalContext, NULL);
} }
else else
{ {
@ -2223,7 +2239,7 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
// context must be a valid Context or NULL // context must be a valid Context or NULL
if(context == NULL || IsContext(context)) if(context == NULL || IsContext(context))
tls_set(LocalContext, context); pthread_setspecific(LocalContext, context);
else else
{ {
alcSetError(NULL, ALC_INVALID_CONTEXT); alcSetError(NULL, ALC_INVALID_CONTEXT);

View File

@ -59,6 +59,32 @@ void pthread_once(pthread_once_t *once, void (*callback)(void))
InterlockedExchange(once, 2); InterlockedExchange(once, 2);
} }
int pthread_key_create(pthread_key_t *key, void (*callback)(void*))
{
*key = TlsAlloc();
if(callback)
InsertUIntMapEntry(&TlsDestructor, *key, callback);
return 0;
}
int pthread_key_delete(pthread_key_t key)
{
InsertUIntMapEntry(&TlsDestructor, key, NULL);
TlsFree(key);
return 0;
}
void *pthread_getspecific(pthread_key_t key)
{ return TlsGetValue(key); }
int pthread_setspecific(pthread_key_t key, void *val)
{
TlsSetValue(key, val);
return 0;
}
void *LoadLib(const char *name) void *LoadLib(const char *name)
{ return LoadLibraryA(name); } { return LoadLibraryA(name); }
void CloseLib(void *handle) void CloseLib(void *handle)

View File

@ -160,6 +160,23 @@ typedef ptrdiff_t ALsizeiptrEXT;
#define RESTRICT #define RESTRICT
#endif #endif
typedef struct UIntMap {
struct {
ALuint key;
ALvoid *value;
} *array;
ALsizei size;
ALsizei maxsize;
} UIntMap;
void InitUIntMap(UIntMap *map);
void ResetUIntMap(UIntMap *map);
ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value);
void RemoveUIntMapKey(UIntMap *map, ALuint key);
ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key);
#ifdef _WIN32 #ifdef _WIN32
#ifndef _WIN32_WINNT #ifndef _WIN32_WINNT
@ -167,11 +184,13 @@ typedef ptrdiff_t ALsizeiptrEXT;
#endif #endif
#include <windows.h> #include <windows.h>
typedef DWORD tls_type; extern UIntMap TlsDestructor;
#define tls_create(x) (*(x) = TlsAlloc())
#define tls_delete(x) TlsFree((x)) typedef DWORD pthread_key_t;
#define tls_get(x) TlsGetValue((x)) int pthread_key_create(pthread_key_t *key, void (*callback)(void*));
#define tls_set(x, a) TlsSetValue((x), (a)) int pthread_key_delete(pthread_key_t key);
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, void *val);
#define HAVE_DYNLOAD 1 #define HAVE_DYNLOAD 1
void *LoadLib(const char *name); void *LoadLib(const char *name);
@ -196,12 +215,6 @@ void pthread_once(pthread_once_t *once, void (*callback)(void));
#define IsBadWritePtr(a,b) ((a) == NULL && (b) != 0) #define IsBadWritePtr(a,b) ((a) == NULL && (b) != 0)
typedef pthread_key_t tls_type;
#define tls_create(x) pthread_key_create((x), NULL)
#define tls_delete(x) pthread_key_delete((x))
#define tls_get(x) pthread_getspecific((x))
#define tls_set(x, a) pthread_setspecific((x), (a))
typedef pthread_mutex_t CRITICAL_SECTION; typedef pthread_mutex_t CRITICAL_SECTION;
void InitializeCriticalSection(CRITICAL_SECTION *cs); void InitializeCriticalSection(CRITICAL_SECTION *cs);
void DeleteCriticalSection(CRITICAL_SECTION *cs); void DeleteCriticalSection(CRITICAL_SECTION *cs);
@ -365,21 +378,6 @@ void alc_loopback_deinit(void);
void alc_loopback_probe(enum DevProbe type); void alc_loopback_probe(enum DevProbe type);
typedef struct UIntMap {
struct {
ALuint key;
ALvoid *value;
} *array;
ALsizei size;
ALsizei maxsize;
} UIntMap;
void InitUIntMap(UIntMap *map);
void ResetUIntMap(UIntMap *map);
ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value);
void RemoveUIntMapKey(UIntMap *map, ALuint key);
ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key);
/* Device formats */ /* Device formats */
enum DevFmtType { enum DevFmtType {
DevFmtByte = AL_BYTE, DevFmtByte = AL_BYTE,