Instead of storing a pointer to a dtor_obj in the TLS key, store a pointer to a pointer as a stable head of the list. This allows the TLS key to be set only once, keeping just the header pointer stable and updating the header pointer to point to the latest addition.
When running destructors, update the header pointer continuously (before running each destructor), to allow it to be updated during the call. (I.e., run_dtor_list is rewritten to use *ptr in each step instead of iterating over a local variable.) This fixes a libcxxabi test case at https://github.com/llvm/llvm-project/blob/llvmorg-16.0.0/libcxxabi/test/thread_local_destruction_order.pass.cpp. Signed-off-by: Martin Storsjö <[email protected]> --- mingw-w64-crt/crt/tls_atexit.c | 48 +++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/mingw-w64-crt/crt/tls_atexit.c b/mingw-w64-crt/crt/tls_atexit.c index f39731ad7..284fd675d 100644 --- a/mingw-w64-crt/crt/tls_atexit.c +++ b/mingw-w64-crt/crt/tls_atexit.c @@ -54,12 +54,13 @@ int __mingw_cxa_atexit(dtor_fn dtor, void *obj, void *dso) { } static void run_dtor_list(dtor_obj **ptr) { - dtor_obj *list = *ptr; - while (list) { - list->dtor(list->obj); - dtor_obj *next = list->next; - free(list); - list = next; + if (!ptr) + return; + while (*ptr) { + dtor_obj *cur = *ptr; + *ptr = cur->next; + cur->dtor(cur->obj); + free(cur); } *ptr = NULL; } @@ -68,28 +69,37 @@ int __mingw_cxa_thread_atexit(dtor_fn dtor, void *obj, void *dso) { if (!inited) return 1; assert(!dso || dso == &__dso_handle); + + dtor_obj **head = (dtor_obj **)TlsGetValue(tls_dtors_slot); + if (!head) { + head = (dtor_obj **) calloc(1, sizeof(*head)); + if (!head) + return 1; + TlsSetValue(tls_dtors_slot, head); + } dtor_obj *handler = (dtor_obj *) calloc(1, sizeof(*handler)); if (!handler) return 1; handler->dtor = dtor; handler->obj = obj; - handler->next = (dtor_obj *)TlsGetValue(tls_dtors_slot); - TlsSetValue(tls_dtors_slot, handler); + handler->next = *head; + *head = handler; return 0; } static void WINAPI tls_atexit_callback(HANDLE __UNUSED_PARAM(hDllHandle), DWORD dwReason, LPVOID __UNUSED_PARAM(lpReserved)) { if (dwReason == DLL_PROCESS_DETACH) { - dtor_obj * p = (dtor_obj *)TlsGetValue(tls_dtors_slot); - run_dtor_list(&p); - TlsSetValue(tls_dtors_slot, p); + dtor_obj **p = (dtor_obj **)TlsGetValue(tls_dtors_slot); + run_dtor_list(p); + free(p); + TlsSetValue(tls_dtors_slot, NULL); TlsFree(tls_dtors_slot); run_dtor_list(&global_dtors); } } static void WINAPI tls_callback(HANDLE hDllHandle, DWORD dwReason, LPVOID __UNUSED_PARAM(lpReserved)) { - dtor_obj * p; + dtor_obj **p; switch (dwReason) { case DLL_PROCESS_ATTACH: if (inited == 0) { @@ -134,9 +144,10 @@ static void WINAPI tls_callback(HANDLE hDllHandle, DWORD dwReason, LPVOID __UNUS * linked CRT (which still runs TLS destructors for the main thread). */ if (__mingw_module_is_dll) { - p = (dtor_obj *)TlsGetValue(tls_dtors_slot); - run_dtor_list(&p); - TlsSetValue(tls_dtors_slot, p); + p = (dtor_obj **)TlsGetValue(tls_dtors_slot); + run_dtor_list(p); + free(p); + TlsSetValue(tls_dtors_slot, NULL); /* For DLLs, run dtors when detached. For EXEs, run dtors via the * thread local atexit callback, to make sure they don't run when * exiting the process with _exit or ExitProcess. */ @@ -151,9 +162,10 @@ static void WINAPI tls_callback(HANDLE hDllHandle, DWORD dwReason, LPVOID __UNUS case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: - p = (dtor_obj *)TlsGetValue(tls_dtors_slot); - run_dtor_list(&p); - TlsSetValue(tls_dtors_slot, p); + p = (dtor_obj **)TlsGetValue(tls_dtors_slot); + run_dtor_list(p); + free(p); + TlsSetValue(tls_dtors_slot, NULL); break; } } -- 2.34.1 _______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
