From 3dbd30649d520543537dd4a95de47f63f6b61f90 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Fri, 7 Aug 2026 12:29:35 +0200 Subject: [PATCH 1/3] Deduplicate minipal thread ID TLS cache. Move the cached thread ID into a single minipal compilation unit instead of emitting one TLS slot per translation unit that includes thread.h. --- src/native/minipal/CMakeLists.txt | 5 ++++- src/native/minipal/thread.c | 8 ++++++++ src/native/minipal/thread.h | 26 +++++++++++++++----------- 3 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 src/native/minipal/thread.c diff --git a/src/native/minipal/CMakeLists.txt b/src/native/minipal/CMakeLists.txt index 32c9497f273c13..bd219f66c97e2f 100644 --- a/src/native/minipal/CMakeLists.txt +++ b/src/native/minipal/CMakeLists.txt @@ -29,7 +29,10 @@ if(NOT WIN32 AND NOT HOST_WASM AND NOT (CLR_CMAKE_TARGET_ARCH_WASM AND NOT CLR_C endif() if(CLR_CMAKE_HOST_UNIX) - list(APPEND SOURCES cpucount.c) + list(APPEND SOURCES + cpucount.c + thread.c + ) endif() # Provide an object library for scenarios where we ship static libraries diff --git a/src/native/minipal/thread.c b/src/native/minipal/thread.c new file mode 100644 index 00000000000000..cd4099c3eed2e1 --- /dev/null +++ b/src/native/minipal/thread.c @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include + +#if !defined(__wasm) || defined(_REENTRANT) +MINIPAL_THREAD_LOCAL size_t minipal_cached_thread_id; +#endif diff --git a/src/native/minipal/thread.h b/src/native/minipal/thread.h index bc1e8c39144501..3fd5c177d36c50 100644 --- a/src/native/minipal/thread.h +++ b/src/native/minipal/thread.h @@ -41,6 +41,14 @@ extern "C" { #endif +#if defined(__GNUC__) && !defined(__clang__) && defined(__cplusplus) +// GCC doesn't support _Thread_local in C++ mode. __thread provides the same +// static TLS initialization semantics without C++ thread_local initialization checks. +#define MINIPAL_THREAD_LOCAL __thread +#else +#define MINIPAL_THREAD_LOCAL _Thread_local +#endif + /** * Get the current thread ID without caching in a TLS variable. * @@ -79,6 +87,10 @@ static inline size_t minipal_get_current_thread_id_no_cache(void) return tid; } +#if !defined(__wasm) || defined(_REENTRANT) +extern MINIPAL_THREAD_LOCAL size_t minipal_cached_thread_id; +#endif + /** * Get the current thread ID. * @@ -90,20 +102,12 @@ static inline size_t minipal_get_current_thread_id(void) return minipal_get_current_thread_id_no_cache(); #else // !__wasm || _REENTRANT -#if defined(__GNUC__) && !defined(__clang__) && defined(__cplusplus) - // gcc doesn't like _Thread_local when __cplusplus is defined. - // although thread_local is C2x, which other compilers don't allow with C11. - static thread_local size_t tid = 0; -#else - static _Thread_local size_t tid = 0; -#endif - - if (!tid) + if (!minipal_cached_thread_id) { - tid = minipal_get_current_thread_id_no_cache(); + minipal_cached_thread_id = minipal_get_current_thread_id_no_cache(); } - return tid; + return minipal_cached_thread_id; #endif // __wasm && !_REENTRANT } From a67f9cbb5d606b7d9fc1590d29139d8b25e236ff Mon Sep 17 00:00:00 2001 From: lateralusX Date: Fri, 7 Aug 2026 12:45:15 +0200 Subject: [PATCH 2/3] Reuse minipal utils PLATFORM_THREAD_LOCAL. --- src/native/minipal/thread.c | 2 +- src/native/minipal/thread.h | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/native/minipal/thread.c b/src/native/minipal/thread.c index cd4099c3eed2e1..be31f8ecc0f6fb 100644 --- a/src/native/minipal/thread.c +++ b/src/native/minipal/thread.c @@ -4,5 +4,5 @@ #include #if !defined(__wasm) || defined(_REENTRANT) -MINIPAL_THREAD_LOCAL size_t minipal_cached_thread_id; +PLATFORM_THREAD_LOCAL size_t minipal_cached_thread_id; #endif diff --git a/src/native/minipal/thread.h b/src/native/minipal/thread.h index 3fd5c177d36c50..1a22d365784d7a 100644 --- a/src/native/minipal/thread.h +++ b/src/native/minipal/thread.h @@ -10,6 +10,7 @@ #include #include #include +#include #if defined(__linux__) #include @@ -41,14 +42,6 @@ extern "C" { #endif -#if defined(__GNUC__) && !defined(__clang__) && defined(__cplusplus) -// GCC doesn't support _Thread_local in C++ mode. __thread provides the same -// static TLS initialization semantics without C++ thread_local initialization checks. -#define MINIPAL_THREAD_LOCAL __thread -#else -#define MINIPAL_THREAD_LOCAL _Thread_local -#endif - /** * Get the current thread ID without caching in a TLS variable. * @@ -88,7 +81,7 @@ static inline size_t minipal_get_current_thread_id_no_cache(void) } #if !defined(__wasm) || defined(_REENTRANT) -extern MINIPAL_THREAD_LOCAL size_t minipal_cached_thread_id; +extern PLATFORM_THREAD_LOCAL size_t minipal_cached_thread_id; #endif /** From d109994a5ebe86af0fe2b1edab3bbe14ae8fac90 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Fri, 7 Aug 2026 13:04:22 +0200 Subject: [PATCH 3/3] Fix build error. --- src/native/minipal/thread.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/native/minipal/thread.c b/src/native/minipal/thread.c index be31f8ecc0f6fb..8e86796289d46c 100644 --- a/src/native/minipal/thread.c +++ b/src/native/minipal/thread.c @@ -1,7 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#include +#include +#include #if !defined(__wasm) || defined(_REENTRANT) PLATFORM_THREAD_LOCAL size_t minipal_cached_thread_id;