Don't use DllMain to call altss destructors

This commit is contained in:
Chris Robinson 2014-04-17 00:56:02 -07:00
parent c3b1c31d9b
commit e5d39a5f4c
3 changed files with 43 additions and 20 deletions

View File

@ -786,34 +786,22 @@ static void alc_init(void);
static void alc_deinit(void);
static void alc_deinit_safe(void);
UIntMap TlsDestructor;
extern UIntMap TlsDestructors;
#ifndef AL_LIBTYPE_STATIC
BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reason, LPVOID lpReserved)
{
ALsizei i;
// Perform actions based on the reason for calling.
switch(ul_reason_for_call)
switch(reason)
{
case DLL_PROCESS_ATTACH:
/* Pin the DLL so we won't get unloaded until the process terminates */
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(WCHAR*)hModule, &hModule);
InitUIntMap(&TlsDestructor, ~0);
InitUIntMap(&TlsDestructors, ~0);
alc_init();
break;
case DLL_THREAD_DETACH:
LockUIntMapRead(&TlsDestructor);
for(i = 0;i < TlsDestructor.size;i++)
{
void *ptr = altss_get(TlsDestructor.array[i].key);
altss_dtor_t callback = (altss_dtor_t)TlsDestructor.array[i].value;
if(ptr && callback)
callback(ptr);
}
UnlockUIntMapRead(&TlsDestructor);
break;
case DLL_PROCESS_DETACH:
@ -821,7 +809,7 @@ BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD ul_reason_for_call,LPVOID lpReserv
alc_deinit();
else
alc_deinit_safe();
ResetUIntMap(&TlsDestructor);
ResetUIntMap(&TlsDestructors);
break;
}
return TRUE;

View File

@ -198,6 +198,42 @@ int almtx_timedlock(almtx_t *mtx, const struct timespec *ts)
}
/* An associative map of uint:void* pairs. The key is the TLS index (given by
* TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits,
* it iterates over the thread-local value for each TLS key and calls the
* destructor function if they're both not NULL. Placing a PIMAGE_TLS_CALLBACK
* function pointer in a ".CRT$XLx" section (where x is a character A to Z)
* ensures the CRT will call it similar to DllMain.
*/
UIntMap TlsDestructors;
static void NTAPI altss_callback(void* UNUSED(handle), DWORD reason, void* UNUSED(reserved))
{
ALsizei i;
if(reason != DLL_THREAD_DETACH)
return;
LockUIntMapRead(&TlsDestructors);
for(i = 0;i < TlsDestructors.size;i++)
{
void *ptr = altss_get(TlsDestructors.array[i].key);
altss_dtor_t callback = (altss_dtor_t)TlsDestructors.array[i].value;
if(ptr && callback)
callback(ptr);
}
UnlockUIntMapRead(&TlsDestructors);
}
#ifdef _MSC_VER
#pragma section(".CRT$XLB",read)
__declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK altss_callback_ = altss_callback;
#elif defined(__GNUC__)
PIMAGE_TLS_CALLBACK altss_callback_ __attribute__((section(".CRT$XLB"))) = altss_callback;
#else
#warning "No TLS callback support, thread-local contexts may leak references on poorly written applications."
PIMAGE_TLS_CALLBACK altss_callback_ = altss_callback;
#endif
int altss_create(altss_t *tss_id, altss_dtor_t callback)
{
DWORD key = TlsAlloc();
@ -206,13 +242,13 @@ int altss_create(altss_t *tss_id, altss_dtor_t callback)
*tss_id = key;
if(callback != NULL)
InsertUIntMapEntry(&TlsDestructor, key, callback);
InsertUIntMapEntry(&TlsDestructors, key, callback);
return althrd_success;
}
void altss_delete(altss_t tss_id)
{
InsertUIntMapEntry(&TlsDestructor, tss_id, NULL);
RemoveUIntMapKey(&TlsDestructors, tss_id);
TlsFree(tss_id);
}

View File

@ -14,7 +14,6 @@ typedef struct UIntMap {
ALsizei limit;
RWLock lock;
} UIntMap;
extern UIntMap TlsDestructor;
void InitUIntMap(UIntMap *map, ALsizei limit);
void ResetUIntMap(UIntMap *map);