summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alc/ALc.c22
-rw-r--r--Alc/threads.c40
-rw-r--r--Alc/uintmap.h1
3 files changed, 43 insertions, 20 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index c4492c96..66ce8579 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -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;
diff --git a/Alc/threads.c b/Alc/threads.c
index e5df3086..ca004903 100644
--- a/Alc/threads.c
+++ b/Alc/threads.c
@@ -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);
}
diff --git a/Alc/uintmap.h b/Alc/uintmap.h
index 2c70f161..6fc1190e 100644
--- a/Alc/uintmap.h
+++ b/Alc/uintmap.h
@@ -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);