Deduplicate minipal thread ID TLS cache. - #131991
Merged
jkotas merged 3 commits intoAug 11, 2026
Merged
Conversation
Move the cached thread ID into a single minipal compilation unit instead of emitting one TLS slot per translation unit that includes thread.h.
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Tagging subscribers to this area: @JulieLeeMSFT, @VSadov |
Contributor
There was a problem hiding this comment.
Pull request overview
Deduplicates the TLS-backed cache used by minipal_get_current_thread_id() by moving the cached thread ID out of a function-local TLS and into a single TLS variable defined in a dedicated minipal compilation unit.
Changes:
- Introduces
MINIPAL_THREAD_LOCALand uses it to declare a shared TLS variableminipal_cached_thread_idinthread.h. - Adds
thread.cto defineminipal_cached_thread_id(under the same WASM/reentrancy guards). - Updates minipal’s CMake source list to compile
thread.con Unix hosts.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/native/minipal/thread.h | Switches the cache from a function-local TLS static to an extern TLS variable and adds a TLS macro. |
| src/native/minipal/thread.c | Defines the shared TLS variable so all translation units refer to the same TLS slot. |
| src/native/minipal/CMakeLists.txt | Ensures thread.c is built into minipal on Unix. |
Member
|
@EgorBot -linux_arm64 --filter "System.Tests.Perf_UInt16.Parse*" |
Member
jkotas
reviewed
Aug 8, 2026
Member
|
@EgorBot -linux_arm64 using BenchmarkDotNet.Attributes;
public class Perf_Enum
{
[Benchmark]
[Arguments(DayOfWeek.Wednesday, "x")]
public string ToString_Format_NonFlags(DayOfWeek value, string format) =>
value.ToString(format);
} |
jkotas
approved these changes
Aug 11, 2026
mdh1418
added a commit
that referenced
this pull request
Aug 13, 2026
Addresses #131991 (comment) Deduplicate the helper functions currently defined with internal linkage in src/native/minipal headers. The affected helpers remain defined as inline in their headers so callers can inline them, but paired .c files now provide one external fallback definition for cases where the compiler emits a call instead. In C, each paired source file does this by including the inline definition and then redeclaring the function with extern. ## C inline linkage A plain C inline definition does not necessarily emit an externally linkable function. At higher optimization levels, the compiler may substitute the header implementation directly at the call site, but at lower optimization levels, or whenever it chooses not to inline, the generated code may call an external symbol. Each paired source file therefore follows this pattern: ``` #include "header.h" extern return_type function(arguments); ``` The header supplies the function body, and the extern redeclaration causes that translation unit to provide the external definition required by non-inlined callers. This preserves access to the inline implementation while avoiding a private `static` copy in every translation unit. ## Out-of-line helpers Based on review feedback, the following helpers are not sufficiently performance-sensitive to justify retaining their implementations in headers: - minipal_getexepath - minipal_get_current_thread_id_no_cache - minipal_set_thread_name Their implementations now live in getexepath.c and thread.c , and their headers contain declarations only. minipal_get_current_thread_id remains inline because its common path is a TLS lookup and branch. It calls the out-of-line uncached implementation only when the TLS cache is empty. Moving minipal_set_thread_name and the uncached thread-ID implementation into thread.c also keeps _GNU_SOURCE source-local. Arbitrary consumers of thread.h no longer compile code requiring GNU-only declarations. ## Executable-path configuration The executable-path implementation uses getauxval(AT_EXECFN) as a Linux fallback when /proc/self/exe cannot be resolved. Availability was previously determined by component-specific generated configuration headers, which were not available to minipal’s source file. Minipal now performs its own getauxval capability check and exposes the result through minipalconfig.h . Because minipal_getexepath has one out-of-line implementation, all callers now use the same capability-tested behavior regardless of optimization level or consumer configuration. ## CPUID linker symbol names The CPUID fallback helpers retain their source-level names, `__cpuid` and `__cpuidex` , to match the corresponding compiler intrinsics. Those names were harmless while the functions were `static` , because each definition had translation-unit-local linkage. Providing external fallback definitions under those names would export reserved double-underscore symbols and could collide with compiler headers or compatibility shims. Assembler-name labels are therefore used to assign minipal-owned linker names: `inline void __cpuid(...) __asm("minipal_cpuid");` `inline void __cpuidex(...) __asm("minipal_cpuidex");` This preserves the existing source-level API while emitting the external symbols as minipal_cpuid and minipal_cpuidex . These labels are separate from the inline assembly inside the function bodies that executes the CPUID instruction. Validation - Built clr+libs+host for Linux x64 Debug. - Verified GCC and Clang C consumers link at -O0 using the external definitions. - Verified optimized consumers can use the inline definitions. - Verified C++ consumers use compatible C-linkage symbols. - Verified the minipal archive provides the expected external helper symbols. - Verified the shipped archives expose minipal_cpuid and minipal_cpuidex rather than strong __cpuid and __cpuidex symbols. - Verified no _SOURCE or _INLINE implementation-control macros remain. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Deduplicate the TLS cache used by
minipal_get_current_thread_id.Fixes #131954.
Root cause
minipal_get_current_thread_idpreviously declared its cached thread ID as a function-localstatic thread_localvariable inthread.h.Because the function has internal linkage, each translation unit using it could emit a separate 8-byte TLS slot. Enabling the in-process crash reporter added another consumer, increasing
libcoreclr.so's TLS footprint enough to exceed glibc's optional static TLS allocation on Linux ARM64.This caused glibc to resolve CoreCLR TLS accesses through
_dl_tlsdesc_dynamicinstead of_dl_tlsdesc_return, adding overhead to allocation, thread-static access, and other common runtime paths.Changes
thread.h.Validation
A test with two independent C and C++ translation units showed: