Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TailCallLoopOpt, W("TailCallLoopOpt"), 1, "Con
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Jit_NetFx40PInvokeStackResilience, W("NetFx40_PInvokeStackResilience"), (DWORD)-1, "Makes P/Invoke resilient against mismatched signature and calling convention (significant perf penalty).")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_DisableOptimizedThreadStaticAccess, W("DisableOptimizedThreadStaticAccess"), (DWORD)0, "Disable the OptimizedThreadStaticAccess feature.")
CONFIG_DWORD_INFO(EXTERNAL_AssertNotStaticTlsResolver, W("AssertNotStaticTlsResolver"), (DWORD)0, "Assert if we attempt to use the static tls resolver path.")
CONFIG_DWORD_INFO(EXTERNAL_AssertStaticTlsResolver, W("AssertStaticTlsResolver"), (DWORD)0, "Assert if the static tls resolver path is not available.")

// AltJitAssertOnNYI should be 0 on targets where JIT is under development or bring up stage, so as to facilitate fallback to main JIT on hitting a NYI.
#if defined(TARGET_X86)
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/vm/threadstatics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,12 @@ bool CanJITOptimizeTLSAccess()
// Optimization is disabled for OpenBSD, which has no addressable __tls_get_addr.
#elif !defined(TARGET_APPLE) && defined(TARGET_UNIX) && (defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64))
bool tlsResolverValid = IsValidTLSResolver();
#ifdef _DEBUG
if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_AssertStaticTlsResolver) != 0)
{
_ASSERTE(tlsResolverValid && "Static TLS resolver is not available");
}
#endif // _DEBUG
if (tlsResolverValid)
{
optimizeThreadStaticAccess = true;
Expand Down
42 changes: 36 additions & 6 deletions src/tests/JIT/Directed/tls/TestTLSWithLoadedDlls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.


// This test is verifying that the runtime properly handles the cases where the TLS infra in the runtime is forced
// to use a dynamic resolver. This is done by means of a private config variable to validate the behavior on Linux Arm64
// and a set of multithreaded tasks, that has been known to cause the runtime to crash when this is handled incorrectly.
// This test verifies that the runtime uses a static TLS resolver by default on Linux Arm64 and properly handles
// the case where loading additional TLS-using libraries forces it to use a dynamic resolver.

using System;
using System.Diagnostics;
Expand All @@ -23,6 +22,15 @@ static class TLSWithLoadedDlls
{
private const int CountOfLibTlsToLoad = 40;

[ThreadStatic]
private static int t_threadStatic;

static int AccessThreadStatic()
{
t_threadStatic = 100;
return t_threadStatic;
}

static async Task DoLotsOfAsyncWork(int loopCount)
{
for (int i = 0; i < loopCount; i++)
Expand All @@ -48,6 +56,23 @@ static int Main(string[] args)
return 100;
}

if ((args.Length == 1) && (args[0] == "AccessThreadStatic"))
{
return AccessThreadStatic();
}

string testAssemblyPath = Assembly.GetExecutingAssembly().Location;
if (OperatingSystem.IsLinux() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
int exitCode = RunChildProcess(
$"{testAssemblyPath} AccessThreadStatic",
"DOTNET_AssertStaticTlsResolver");
if (exitCode != 100)
{
return exitCode;
}
}

int CountOfLibTlsToLoad = 60;

if (OperatingSystem.IsWindows()) // Windows does not have a really long command line length limit, and doesn't have a problem with many TLS using images used
Expand Down Expand Up @@ -79,14 +104,19 @@ static int Main(string[] args)
}

arguments.Append(' ');
arguments.Append(System.Reflection.Assembly.GetExecutingAssembly().Location);
arguments.Append(testAssemblyPath);
arguments.Append(" RunLotsOfTasks");

return RunChildProcess(arguments.ToString(), "DOTNET_AssertNotStaticTlsResolver");
}

private static int RunChildProcess(string arguments, string assertionVariable)
{
Process process = new Process();
process.StartInfo.FileName = GetCorerunPath();
Comment on lines +113 to 116
process.StartInfo.Arguments = arguments.ToString();
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.EnvironmentVariables["DOTNET_AssertNotStaticTlsResolver"] = "1";
process.StartInfo.EnvironmentVariables[assertionVariable] = "1";

Console.WriteLine($"Launching {process.StartInfo.FileName} {process.StartInfo.Arguments}");

Expand Down