From 1e365190d0b6a1be2a4df0301cffb704dede6dcc Mon Sep 17 00:00:00 2001 From: "Asanka C. Herath" Date: Thu, 4 Nov 2010 18:06:41 -0400 Subject: [PATCH] Windows: Manage thread local storage manually in dlfcn_w32 --- lib/roken/dlfcn_w32.c | 75 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/lib/roken/dlfcn_w32.c b/lib/roken/dlfcn_w32.c index 5898f1682..d7eab07c2 100644 --- a/lib/roken/dlfcn_w32.c +++ b/lib/roken/dlfcn_w32.c @@ -36,17 +36,75 @@ #define ERR_STR_LEN 256 -__declspec(thread) static char err_str[ERR_STR_LEN]; +static volatile DWORD dlfcn_tls = TLS_OUT_OF_INDEXES; -static void set_error(const char * e) { - StringCbCopy(err_str, sizeof(err_str), e); +static DWORD get_tl_error_slot(void) +{ + if (dlfcn_tls == TLS_OUT_OF_INDEXES) { + DWORD slot = TlsAlloc(); + DWORD old_slot; + + if (slot == TLS_OUT_OF_INDEXES) + return dlfcn_tls; + + if ((old_slot = InterlockedCompareExchange(&dlfcn_tls, slot, + TLS_OUT_OF_INDEXES)) != + TLS_OUT_OF_INDEXES) { + + /* Lost a race */ + TlsFree(slot); + return old_slot; + } else { + return slot; + } + } + + return dlfcn_tls; +} + +static void set_error(const char * e) +{ + char * s; + char * old_s; + size_t len; + + DWORD slot = get_tl_error_slot(); + + if (slot == TLS_OUT_OF_INDEXES) + return; + + len = strlen(e) * sizeof(char) + sizeof(char); + s = LocalAlloc(LMEM_FIXED, len); + if (s == NULL) + return; + + old_s = (char *) TlsGetValue(slot); + TlsSetValue(slot, (LPVOID) s); + + if (old_s != NULL) + LocalFree(old_s); } static void set_error_from_last(void) { - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + DWORD slot = get_tl_error_slot(); + char * s = NULL; + char * old_s; + + if (slot == TLS_OUT_OF_INDEXES) + return; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, GetLastError(), 0, - err_str, sizeof(err_str)/sizeof(err_str[0]), + (LPTSTR) &s, 0, NULL); + if (s == NULL) + return; + + old_s = (char *) TlsGetValue(slot); + TlsSetValue(slot, (LPVOID) s); + + if (old_s != NULL) + LocalFree(old_s); } ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL @@ -64,7 +122,12 @@ dlclose(void * vhm) ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL dlerror(void) { - return err_str; + DWORD slot = get_tl_error_slot(); + + if (slot == TLS_OUT_OF_INDEXES) + return NULL; + + return (char *) TlsGetValue(slot); } ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL