From a6e4834d53ac591a4b3d4a213a8928ad685f7ad8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 23:54:17 -0800 Subject: [PATCH] [release/8.0] Free the tls memory on thread termination (#95439) * Free the tls memory * zero the size variables * fix linux build errors * Move ThreadStaticBlockInfo definition in jitinterface.h * cleanup and consolidate TLS variables * Address review feedback * reset t_NonGCThreadStaticBlocksSize and conditional check the nullptr * Delete tls memory from detach thread * Call DeleteThreadLocalMemory() from TlsDestructionMonitor --------- Co-authored-by: Kunal Pathak --- src/coreclr/vm/ceemain.cpp | 30 ++++++++++++++++++++++++++++++ src/coreclr/vm/ceemain.h | 2 ++ src/coreclr/vm/jithelpers.cpp | 21 +++++---------------- src/coreclr/vm/jitinterface.cpp | 19 ++----------------- src/coreclr/vm/jitinterface.h | 19 +++++++++++++++++++ 5 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 1fd898684cf1c..1c58c941fb21a 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -1752,6 +1752,7 @@ struct TlsDestructionMonitor GCX_COOP_NO_DTOR_END(); } thread->DetachThread(TRUE); + DeleteThreadLocalMemory(); } ThreadDetaching(); @@ -1768,6 +1769,35 @@ void EnsureTlsDestructionMonitor() tls_destructionMonitor.Activate(); } +#ifdef _MSC_VER +__declspec(thread) ThreadStaticBlockInfo t_ThreadStatics; +#else +__thread ThreadStaticBlockInfo t_ThreadStatics; +#endif // _MSC_VER + +// Delete the thread local memory only if we the current thread +// is the one executing this code. If we do not guard it, it will +// end up deleting the thread local memory of the calling thread. +void DeleteThreadLocalMemory() +{ + t_NonGCThreadStaticBlocksSize = 0; + t_GCThreadStaticBlocksSize = 0; + + t_ThreadStatics.NonGCMaxThreadStaticBlocks = 0; + t_ThreadStatics.GCMaxThreadStaticBlocks = 0; + + if (t_ThreadStatics.NonGCThreadStaticBlocks != nullptr) + { + delete[] t_ThreadStatics.NonGCThreadStaticBlocks; + t_ThreadStatics.NonGCThreadStaticBlocks = nullptr; + } + if (t_ThreadStatics.GCThreadStaticBlocks != nullptr) + { + delete[] t_ThreadStatics.GCThreadStaticBlocks; + t_ThreadStatics.GCThreadStaticBlocks = nullptr; + } +} + #ifdef DEBUGGING_SUPPORTED // // InitializeDebugger initialized the Runtime-side COM+ Debugging Services diff --git a/src/coreclr/vm/ceemain.h b/src/coreclr/vm/ceemain.h index 1404a5a04237f..85efc8d0a9c78 100644 --- a/src/coreclr/vm/ceemain.h +++ b/src/coreclr/vm/ceemain.h @@ -47,6 +47,8 @@ void ThreadDetaching(); void EnsureTlsDestructionMonitor(); +void DeleteThreadLocalMemory(); + void SetLatchedExitCode (INT32 code); INT32 GetLatchedExitCode (void); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index e225a6e3834b7..744d80eb34971 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1777,24 +1777,13 @@ HCIMPL1(void*, JIT_GetGCThreadStaticBase_Helper, MethodTable * pMT) } HCIMPLEND -struct ThreadStaticBlockInfo -{ - uint32_t NonGCMaxThreadStaticBlocks; - void** NonGCThreadStaticBlocks; - - uint32_t GCMaxThreadStaticBlocks; - void** GCThreadStaticBlocks; -}; - #ifdef _MSC_VER -__declspec(selectany) __declspec(thread) ThreadStaticBlockInfo t_ThreadStatics; -__declspec(selectany) __declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize; -__declspec(selectany) __declspec(thread) uint32_t t_GCThreadStaticBlocksSize; +__declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize; +__declspec(thread) uint32_t t_GCThreadStaticBlocksSize; #else -EXTERN_C __thread ThreadStaticBlockInfo t_ThreadStatics; -EXTERN_C __thread uint32_t t_NonGCThreadStaticBlocksSize; -EXTERN_C __thread uint32_t t_GCThreadStaticBlocksSize; -#endif +__thread uint32_t t_NonGCThreadStaticBlocksSize; +__thread uint32_t t_GCThreadStaticBlocksSize; +#endif // !_MSC_VER // *** This helper corresponds to both CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE and // CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR. Even though we always check diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 74ee2f7482e74..1cc6c37e09c22 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -69,24 +69,9 @@ EXTERN_C uint32_t _tls_index; #endif -struct ThreadStaticBlockInfo -{ - uint32_t NonGCMaxThreadStaticBlocks; - void** NonGCThreadStaticBlocks; - - uint32_t GCMaxThreadStaticBlocks; - void** GCThreadStaticBlocks; -}; -#ifdef _MSC_VER -__declspec(selectany) __declspec(thread) ThreadStaticBlockInfo t_ThreadStatics; -__declspec(selectany) __declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize; -__declspec(selectany) __declspec(thread) uint32_t t_GCThreadStaticBlocksSize; -#else +#ifndef _MSC_VER extern "C" void* __tls_get_addr(void* ti); -__thread ThreadStaticBlockInfo t_ThreadStatics; -__thread uint32_t t_NonGCThreadStaticBlocksSize; -__thread uint32_t t_GCThreadStaticBlocksSize; -#endif // _MSC_VER +#endif // !_MSC_VER // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro // diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index b6e5eff8ff427..fa92a18501df2 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -101,6 +101,25 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, #endif // TARGET_X86 +// thread local struct to store the "thread static blocks" +struct ThreadStaticBlockInfo +{ + uint32_t NonGCMaxThreadStaticBlocks; + void** NonGCThreadStaticBlocks; + + uint32_t GCMaxThreadStaticBlocks; + void** GCThreadStaticBlocks; +}; + +#ifdef _MSC_VER +EXTERN_C __declspec(thread) ThreadStaticBlockInfo t_ThreadStatics; +EXTERN_C __declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize; +EXTERN_C __declspec(thread) uint32_t t_GCThreadStaticBlocksSize; +#else +EXTERN_C __thread ThreadStaticBlockInfo t_ThreadStatics; +EXTERN_C __thread uint32_t t_NonGCThreadStaticBlocksSize; +EXTERN_C __thread uint32_t t_GCThreadStaticBlocksSize; +#endif // _MSC_VER // // JIT HELPER ALIASING FOR PORTABILITY.