From f76e743fb1ac1dc7d1951c55b06e60f7bb11afbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 20 Aug 2025 16:25:12 +0200 Subject: [PATCH 01/11] Fix deadlock when creating threads from ModuleInitializer in a shared library The problem is that the first time we reverse p/invoke into an API in the shared library, we need to do two things: initialize runtime and run module initializers. Running module initializers is done as part of runtime initialization in the shared library case because it was convenient to do it there (in the EXE case, we run them after runtime initialization, right before Main). The problem with running it as part of the runtime initialization is that the arbitrary user code can deadlock us (see the issues for stack). This separates runtime initialization and running module initializers. Doing just that doesn't fix the problem though because the deadlock we saw is part of thread creation. So we'd just deadlock on the module initializer runner. This introduces a new kind of reverse p/invoke enter routine that doesn't wait for module initializers. Instead we wait for module initializers before we are ready to run user code on the thread (and the thread is initialized just enough that ThreadStart can make progress). This also fixes a potential issue in the EXE case where threads created from module initializers could start running before we're finished running module initializers. Instead this introduces a new opportunity for deadlocking :(. I don't actually like this fix. But we need to do something about it because EventSource does exactly this (#118773). Fixes #118773. Fixes #107699. --- src/coreclr/nativeaot/Bootstrap/main.cpp | 5 +- .../CompilerHelpers/StartupCodeHelpers.cs | 12 +++++ src/coreclr/nativeaot/Runtime/thread.cpp | 50 ++++++++++++++++--- src/coreclr/nativeaot/Runtime/thread.h | 3 +- .../System/Threading/Thread.NativeAot.Unix.cs | 6 +++ .../Threading/Thread.NativeAot.Windows.cs | 6 +++ .../src/System/Threading/Thread.NativeAot.cs | 5 ++ .../tools/Common/JitInterface/CorInfoImpl.cs | 12 +++++ .../StartupCode/NativeLibraryStartupMethod.cs | 9 ---- .../SmokeTests/SharedLibrary/SharedLibrary.cs | 16 +++++- 10 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 57eb0012666e1b..efe753b84663d6 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -99,7 +99,7 @@ static char& __unbox_z = __stop___unbox; #endif // _MSC_VER extern "C" bool RhInitialize(bool isDll); -extern "C" void RhSetRuntimeInitializationCallback(int (*fPtr)()); +extern "C" void RhSetRuntimeInitializationCallback(int (*fRuntimeInit)(), void (*fModuleInit)()); extern "C" bool RhRegisterOSModule(void * pModule, void * pvManagedCodeStartRange, uint32_t cbManagedCodeRange, @@ -176,6 +176,7 @@ extern "C" int __managed__Main(int argc, char* argv[]); #else #define NATIVEAOT_ENTRYPOINT __managed__Startup extern "C" void __managed__Startup(); +extern "C" void RunModuleInitializers(); #endif // !NATIVEAOT_DLL static int InitializeRuntime() @@ -248,7 +249,7 @@ static struct InitializeRuntimePointerHelper { InitializeRuntimePointerHelper() { - RhSetRuntimeInitializationCallback(&InitializeRuntime); + RhSetRuntimeInitializationCallback(&InitializeRuntime, &RunModuleInitializers); } } initializeRuntimePointerHelper; #endif // NATIVEAOT_DLL diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs index 039b586c01eccc..ff7a0e763ffa7d 100644 --- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs +++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs @@ -22,6 +22,8 @@ internal static partial class StartupCodeHelpers /// private static int s_moduleCount; + internal static volatile bool s_runningModuleInitializers; + /// /// GC handle of an array with s_moduleCount elements, each representing and array of GC static bases of the types in the module. /// @@ -160,12 +162,22 @@ private static unsafe void InitializeModuleFrozenObjectSegment(IntPtr segmentSta } } + [UnmanagedCallersOnly(EntryPoint = "RunModuleInitializers")] + internal static void RunModuleInitializers2() + { + RunModuleInitializers(); + } + internal static void RunModuleInitializers() { + s_runningModuleInitializers = true; + for (int i = 0; i < s_moduleCount; i++) { RunInitializers(s_modules[i], ReadyToRunSectionType.ModuleInitializerList); } + + s_runningModuleInitializers = false; } private static unsafe void RunInitializers(TypeManagerHandle typeManager, ReadyToRunSectionType section) diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index 45b88d1cde2def..dc9b354e43cfc8 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -32,7 +32,9 @@ #ifndef DACCESS_COMPILE static int (*g_RuntimeInitializationCallback)(); +static void (*g_ModuleInitializerCallback)(); static Thread* g_RuntimeInitializingThread; +static Thread* g_ModuleInitializingThread; #endif //!DACCESS_COMPILE @@ -1188,12 +1190,13 @@ EXTERN_C uint32_t QCALLTYPE RhCompatibleReentrantWaitAny(UInt32_BOOL alertable, } #endif // TARGET_UNIX -EXTERN_C void RhSetRuntimeInitializationCallback(int (*fPtr)()) +EXTERN_C void RhSetRuntimeInitializationCallback(int (*fRuntimeInit)(), void (*fModuleInit)()) { - g_RuntimeInitializationCallback = fPtr; + g_RuntimeInitializationCallback = fRuntimeInit; + g_ModuleInitializerCallback = fModuleInit; } -void Thread::ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame) +void Thread::ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame, bool fEnsureModuleInitializersExecuted) { if (!IsStateSet(TSF_Attached)) { @@ -1202,6 +1205,14 @@ void Thread::ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame) EnsureRuntimeInitialized(); } + // Additionally check g_RuntimeInitializingThread to cover the case where we're currently running EnsureRuntimeInitialized + // on this thread but we need a reverse p/invoke transition. Module initializers should only run after the runtime + // is initialized. + if (fEnsureModuleInitializersExecuted && g_ModuleInitializerCallback != NULL && g_ModuleInitializingThread != this && g_RuntimeInitializingThread != this) + { + EnsureModuleInitializersExecuted(); + } + ThreadStore::AttachCurrentThread(); } @@ -1249,6 +1260,22 @@ void Thread::EnsureRuntimeInitialized() PalInterlockedExchangePointer((void *volatile *)&g_RuntimeInitializingThread, NULL); } +void Thread::EnsureModuleInitializersExecuted() +{ + while (PalInterlockedCompareExchangePointer((void *volatile *)&g_ModuleInitializingThread, this, NULL) != NULL) + { + PalSleep(1); + } + + if (g_ModuleInitializerCallback != NULL) + { + g_ModuleInitializerCallback(); + g_ModuleInitializerCallback = NULL; + } + + PalInterlockedExchangePointer((void *volatile *)&g_ModuleInitializingThread, NULL); +} + Object * Thread::GetThreadAbortException() { return m_threadAbortException; @@ -1324,10 +1351,10 @@ FCIMPL0(size_t, RhGetDefaultStackSize) FCIMPLEND // Standard calling convention variant and actual implementation for RhpReversePInvokeAttachOrTrapThread -EXTERN_C NOINLINE void FASTCALL RhpReversePInvokeAttachOrTrapThread2(ReversePInvokeFrame* pFrame) +EXTERN_C NOINLINE void FASTCALL RhpReversePInvokeAttachOrTrapThread2(ReversePInvokeFrame* pFrame, bool fEnsureModuleInitializersExecuted) { ASSERT(pFrame->m_savedThread == ThreadStore::RawGetCurrentThread()); - pFrame->m_savedThread->ReversePInvokeAttachOrTrapThread(pFrame); + pFrame->m_savedThread->ReversePInvokeAttachOrTrapThread(pFrame, fEnsureModuleInitializersExecuted); } // @@ -1341,7 +1368,18 @@ FCIMPL1(void, RhpReversePInvoke, ReversePInvokeFrame * pFrame) if (pCurThread->InlineTryFastReversePInvoke(pFrame)) return; - RhpReversePInvokeAttachOrTrapThread2(pFrame); + RhpReversePInvokeAttachOrTrapThread2(pFrame, true); +} +FCIMPLEND + +FCIMPL1(void, RhpReversePInvokeNoModuleInitializer, ReversePInvokeFrame * pFrame) +{ + Thread * pCurThread = ThreadStore::RawGetCurrentThread(); + pFrame->m_savedThread = pCurThread; + if (pCurThread->InlineTryFastReversePInvoke(pFrame)) + return; + + RhpReversePInvokeAttachOrTrapThread2(pFrame, false); } FCIMPLEND diff --git a/src/coreclr/nativeaot/Runtime/thread.h b/src/coreclr/nativeaot/Runtime/thread.h index 83249cfc6bc77e..e33105b6137639 100644 --- a/src/coreclr/nativeaot/Runtime/thread.h +++ b/src/coreclr/nativeaot/Runtime/thread.h @@ -240,6 +240,7 @@ class Thread : private RuntimeThreadLocals bool CacheTransitionFrameForSuspend(); void ResetCachedTransitionFrame(); void EnsureRuntimeInitialized(); + void EnsureModuleInitializersExecuted(); // // SyncState members @@ -352,7 +353,7 @@ class Thread : private RuntimeThreadLocals // void WaitForGC(PInvokeTransitionFrame* pTransitionFrame); - void ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame); + void ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame, bool fEnsureModuleInitializersExecuted); bool InlineTryFastReversePInvoke(ReversePInvokeFrame * pFrame); void InlineReversePInvokeReturn(ReversePInvokeFrame * pFrame); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs index de77bc91b088e3..e1d6b772a15c9c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs @@ -115,6 +115,12 @@ private unsafe bool CreateThread(GCHandle thisThreadHandle) /// /// This is an entry point for managed threads created by application /// + ///////////////////////////////////////////////////////////////////////// + // WARNING: The compiler special cases this UnmanagedCallersOnly method + // and performs a "lite" reverse p/invoke transition that will not wait + // for module initializers before starting to run this method. + // We wait for module initializers later in StartThread manually. + ///////////////////////////////////////////////////////////////////////// [UnmanagedCallersOnly] private static IntPtr ThreadEntryPoint(IntPtr parameter) { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs index f01fe0f86f38f7..401180c463581b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs @@ -219,6 +219,12 @@ private unsafe bool CreateThread(GCHandle thisThreadHandle) /// /// This is an entry point for managed threads created by application /// + ///////////////////////////////////////////////////////////////////////// + // WARNING: The compiler special cases this UnmanagedCallersOnly method + // and performs a "lite" reverse p/invoke transition that will not wait + // for module initializers before starting to run this method. + // We wait for module initializers later in StartThread manually. + ///////////////////////////////////////////////////////////////////////// [UnmanagedCallersOnly] private static uint ThreadEntryPoint(IntPtr parameter) { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs index 3758fca9e8a0a2..27f31c220dc1c6 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs @@ -450,6 +450,11 @@ private static void StartThread(IntPtr parameter) IncrementRunningForeground(); } + while (Internal.Runtime.CompilerHelpers.StartupCodeHelpers.s_runningModuleInitializers) + { + Yield(); + } + try { StartHelper? startHelper = thread._startHelper; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index e6fd0d4f7f80e0..dde156e938260e 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3552,6 +3552,18 @@ private void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP *pNativeE entryPoint = GetHelperFtnUncached(ftnNum); _helperCache.Add(ftnNum, entryPoint); } + +#if !READYTORUN + if (ftnNum == CorInfoHelpFunc.CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER + && MethodBeingCompiled.Name == "ThreadEntryPoint" + && MethodBeingCompiled.OwningType is MetadataType mdOwningType + && mdOwningType.Module == _compilation.TypeSystemContext.SystemModule + && mdOwningType is { Name: "Thread", Namespace: "System.Threading" }) + { + entryPoint = _compilation.NodeFactory.ExternFunctionSymbol("RhpReversePInvokeNoModuleInitializer"); + } +#endif + if (entryPoint.RepresentsIndirectionCell) { pNativeEntrypoint->addr = (void*)ObjectToHandle(entryPoint); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/NativeLibraryStartupMethod.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/NativeLibraryStartupMethod.cs index 160a06bb441a2d..0bbd2e656042f7 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/NativeLibraryStartupMethod.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/NativeLibraryStartupMethod.cs @@ -69,15 +69,6 @@ public override MethodIL EmitIL() } } - MetadataType startup = Context.GetOptionalHelperType("StartupCodeHelpers"); - - // Run module initializers - MethodDesc runModuleInitializers = startup?.GetMethod("RunModuleInitializers", null); - if (runModuleInitializers != null) - { - codeStream.Emit(ILOpcode.call, emitter.NewToken(runModuleInitializers)); - } - codeStream.Emit(ILOpcode.ret); return emitter.Link(this); } diff --git a/src/tests/nativeaot/SmokeTests/SharedLibrary/SharedLibrary.cs b/src/tests/nativeaot/SmokeTests/SharedLibrary/SharedLibrary.cs index a6c2c7e74ec1c3..14219c91764e07 100644 --- a/src/tests/nativeaot/SmokeTests/SharedLibrary/SharedLibrary.cs +++ b/src/tests/nativeaot/SmokeTests/SharedLibrary/SharedLibrary.cs @@ -4,15 +4,29 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; namespace SharedLibrary { public class ClassLibrary { + static Thread s_setterThread; + static int s_primitiveInt; + + [ModuleInitializer] + public static void CreateThreadInModuleInitializer() + { + // Regression test for https://github.com/dotnet/runtime/issues/107699 + // where creating threads in module initializer would lead to a deadlock. + s_setterThread = new Thread(() => { s_primitiveInt = 10; }); + s_setterThread.Start(); + } + [UnmanagedCallersOnly(EntryPoint = "ReturnsPrimitiveInt", CallConvs = new Type[] { typeof(CallConvStdcall) })] public static int ReturnsPrimitiveInt() { - return 10; + s_setterThread.Join(); + return s_primitiveInt; } [UnmanagedCallersOnly(EntryPoint = "ReturnsPrimitiveBool", CallConvs = new Type[] { typeof(CallConvStdcall) })] From 1f5d0ada3124bf90875419b713e63836f8e292ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 21 Aug 2025 08:10:19 +0200 Subject: [PATCH 02/11] Revert everything but the test --- src/coreclr/nativeaot/Bootstrap/main.cpp | 5 +- .../CompilerHelpers/StartupCodeHelpers.cs | 12 ----- src/coreclr/nativeaot/Runtime/thread.cpp | 50 +++---------------- src/coreclr/nativeaot/Runtime/thread.h | 3 +- .../System/Threading/Thread.NativeAot.Unix.cs | 6 --- .../Threading/Thread.NativeAot.Windows.cs | 6 --- .../src/System/Threading/Thread.NativeAot.cs | 5 -- .../tools/Common/JitInterface/CorInfoImpl.cs | 12 ----- .../StartupCode/NativeLibraryStartupMethod.cs | 9 ++++ 9 files changed, 18 insertions(+), 90 deletions(-) diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index efe753b84663d6..57eb0012666e1b 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -99,7 +99,7 @@ static char& __unbox_z = __stop___unbox; #endif // _MSC_VER extern "C" bool RhInitialize(bool isDll); -extern "C" void RhSetRuntimeInitializationCallback(int (*fRuntimeInit)(), void (*fModuleInit)()); +extern "C" void RhSetRuntimeInitializationCallback(int (*fPtr)()); extern "C" bool RhRegisterOSModule(void * pModule, void * pvManagedCodeStartRange, uint32_t cbManagedCodeRange, @@ -176,7 +176,6 @@ extern "C" int __managed__Main(int argc, char* argv[]); #else #define NATIVEAOT_ENTRYPOINT __managed__Startup extern "C" void __managed__Startup(); -extern "C" void RunModuleInitializers(); #endif // !NATIVEAOT_DLL static int InitializeRuntime() @@ -249,7 +248,7 @@ static struct InitializeRuntimePointerHelper { InitializeRuntimePointerHelper() { - RhSetRuntimeInitializationCallback(&InitializeRuntime, &RunModuleInitializers); + RhSetRuntimeInitializationCallback(&InitializeRuntime); } } initializeRuntimePointerHelper; #endif // NATIVEAOT_DLL diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs index ff7a0e763ffa7d..039b586c01eccc 100644 --- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs +++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs @@ -22,8 +22,6 @@ internal static partial class StartupCodeHelpers /// private static int s_moduleCount; - internal static volatile bool s_runningModuleInitializers; - /// /// GC handle of an array with s_moduleCount elements, each representing and array of GC static bases of the types in the module. /// @@ -162,22 +160,12 @@ private static unsafe void InitializeModuleFrozenObjectSegment(IntPtr segmentSta } } - [UnmanagedCallersOnly(EntryPoint = "RunModuleInitializers")] - internal static void RunModuleInitializers2() - { - RunModuleInitializers(); - } - internal static void RunModuleInitializers() { - s_runningModuleInitializers = true; - for (int i = 0; i < s_moduleCount; i++) { RunInitializers(s_modules[i], ReadyToRunSectionType.ModuleInitializerList); } - - s_runningModuleInitializers = false; } private static unsafe void RunInitializers(TypeManagerHandle typeManager, ReadyToRunSectionType section) diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index dc9b354e43cfc8..45b88d1cde2def 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -32,9 +32,7 @@ #ifndef DACCESS_COMPILE static int (*g_RuntimeInitializationCallback)(); -static void (*g_ModuleInitializerCallback)(); static Thread* g_RuntimeInitializingThread; -static Thread* g_ModuleInitializingThread; #endif //!DACCESS_COMPILE @@ -1190,13 +1188,12 @@ EXTERN_C uint32_t QCALLTYPE RhCompatibleReentrantWaitAny(UInt32_BOOL alertable, } #endif // TARGET_UNIX -EXTERN_C void RhSetRuntimeInitializationCallback(int (*fRuntimeInit)(), void (*fModuleInit)()) +EXTERN_C void RhSetRuntimeInitializationCallback(int (*fPtr)()) { - g_RuntimeInitializationCallback = fRuntimeInit; - g_ModuleInitializerCallback = fModuleInit; + g_RuntimeInitializationCallback = fPtr; } -void Thread::ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame, bool fEnsureModuleInitializersExecuted) +void Thread::ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame) { if (!IsStateSet(TSF_Attached)) { @@ -1205,14 +1202,6 @@ void Thread::ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame, bool EnsureRuntimeInitialized(); } - // Additionally check g_RuntimeInitializingThread to cover the case where we're currently running EnsureRuntimeInitialized - // on this thread but we need a reverse p/invoke transition. Module initializers should only run after the runtime - // is initialized. - if (fEnsureModuleInitializersExecuted && g_ModuleInitializerCallback != NULL && g_ModuleInitializingThread != this && g_RuntimeInitializingThread != this) - { - EnsureModuleInitializersExecuted(); - } - ThreadStore::AttachCurrentThread(); } @@ -1260,22 +1249,6 @@ void Thread::EnsureRuntimeInitialized() PalInterlockedExchangePointer((void *volatile *)&g_RuntimeInitializingThread, NULL); } -void Thread::EnsureModuleInitializersExecuted() -{ - while (PalInterlockedCompareExchangePointer((void *volatile *)&g_ModuleInitializingThread, this, NULL) != NULL) - { - PalSleep(1); - } - - if (g_ModuleInitializerCallback != NULL) - { - g_ModuleInitializerCallback(); - g_ModuleInitializerCallback = NULL; - } - - PalInterlockedExchangePointer((void *volatile *)&g_ModuleInitializingThread, NULL); -} - Object * Thread::GetThreadAbortException() { return m_threadAbortException; @@ -1351,10 +1324,10 @@ FCIMPL0(size_t, RhGetDefaultStackSize) FCIMPLEND // Standard calling convention variant and actual implementation for RhpReversePInvokeAttachOrTrapThread -EXTERN_C NOINLINE void FASTCALL RhpReversePInvokeAttachOrTrapThread2(ReversePInvokeFrame* pFrame, bool fEnsureModuleInitializersExecuted) +EXTERN_C NOINLINE void FASTCALL RhpReversePInvokeAttachOrTrapThread2(ReversePInvokeFrame* pFrame) { ASSERT(pFrame->m_savedThread == ThreadStore::RawGetCurrentThread()); - pFrame->m_savedThread->ReversePInvokeAttachOrTrapThread(pFrame, fEnsureModuleInitializersExecuted); + pFrame->m_savedThread->ReversePInvokeAttachOrTrapThread(pFrame); } // @@ -1368,18 +1341,7 @@ FCIMPL1(void, RhpReversePInvoke, ReversePInvokeFrame * pFrame) if (pCurThread->InlineTryFastReversePInvoke(pFrame)) return; - RhpReversePInvokeAttachOrTrapThread2(pFrame, true); -} -FCIMPLEND - -FCIMPL1(void, RhpReversePInvokeNoModuleInitializer, ReversePInvokeFrame * pFrame) -{ - Thread * pCurThread = ThreadStore::RawGetCurrentThread(); - pFrame->m_savedThread = pCurThread; - if (pCurThread->InlineTryFastReversePInvoke(pFrame)) - return; - - RhpReversePInvokeAttachOrTrapThread2(pFrame, false); + RhpReversePInvokeAttachOrTrapThread2(pFrame); } FCIMPLEND diff --git a/src/coreclr/nativeaot/Runtime/thread.h b/src/coreclr/nativeaot/Runtime/thread.h index e33105b6137639..83249cfc6bc77e 100644 --- a/src/coreclr/nativeaot/Runtime/thread.h +++ b/src/coreclr/nativeaot/Runtime/thread.h @@ -240,7 +240,6 @@ class Thread : private RuntimeThreadLocals bool CacheTransitionFrameForSuspend(); void ResetCachedTransitionFrame(); void EnsureRuntimeInitialized(); - void EnsureModuleInitializersExecuted(); // // SyncState members @@ -353,7 +352,7 @@ class Thread : private RuntimeThreadLocals // void WaitForGC(PInvokeTransitionFrame* pTransitionFrame); - void ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame, bool fEnsureModuleInitializersExecuted); + void ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame); bool InlineTryFastReversePInvoke(ReversePInvokeFrame * pFrame); void InlineReversePInvokeReturn(ReversePInvokeFrame * pFrame); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs index e1d6b772a15c9c..de77bc91b088e3 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs @@ -115,12 +115,6 @@ private unsafe bool CreateThread(GCHandle thisThreadHandle) /// /// This is an entry point for managed threads created by application /// - ///////////////////////////////////////////////////////////////////////// - // WARNING: The compiler special cases this UnmanagedCallersOnly method - // and performs a "lite" reverse p/invoke transition that will not wait - // for module initializers before starting to run this method. - // We wait for module initializers later in StartThread manually. - ///////////////////////////////////////////////////////////////////////// [UnmanagedCallersOnly] private static IntPtr ThreadEntryPoint(IntPtr parameter) { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs index 401180c463581b..f01fe0f86f38f7 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs @@ -219,12 +219,6 @@ private unsafe bool CreateThread(GCHandle thisThreadHandle) /// /// This is an entry point for managed threads created by application /// - ///////////////////////////////////////////////////////////////////////// - // WARNING: The compiler special cases this UnmanagedCallersOnly method - // and performs a "lite" reverse p/invoke transition that will not wait - // for module initializers before starting to run this method. - // We wait for module initializers later in StartThread manually. - ///////////////////////////////////////////////////////////////////////// [UnmanagedCallersOnly] private static uint ThreadEntryPoint(IntPtr parameter) { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs index 27f31c220dc1c6..3758fca9e8a0a2 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs @@ -450,11 +450,6 @@ private static void StartThread(IntPtr parameter) IncrementRunningForeground(); } - while (Internal.Runtime.CompilerHelpers.StartupCodeHelpers.s_runningModuleInitializers) - { - Yield(); - } - try { StartHelper? startHelper = thread._startHelper; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index dde156e938260e..e6fd0d4f7f80e0 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3552,18 +3552,6 @@ private void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP *pNativeE entryPoint = GetHelperFtnUncached(ftnNum); _helperCache.Add(ftnNum, entryPoint); } - -#if !READYTORUN - if (ftnNum == CorInfoHelpFunc.CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER - && MethodBeingCompiled.Name == "ThreadEntryPoint" - && MethodBeingCompiled.OwningType is MetadataType mdOwningType - && mdOwningType.Module == _compilation.TypeSystemContext.SystemModule - && mdOwningType is { Name: "Thread", Namespace: "System.Threading" }) - { - entryPoint = _compilation.NodeFactory.ExternFunctionSymbol("RhpReversePInvokeNoModuleInitializer"); - } -#endif - if (entryPoint.RepresentsIndirectionCell) { pNativeEntrypoint->addr = (void*)ObjectToHandle(entryPoint); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/NativeLibraryStartupMethod.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/NativeLibraryStartupMethod.cs index 0bbd2e656042f7..160a06bb441a2d 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/NativeLibraryStartupMethod.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/Stubs/StartupCode/NativeLibraryStartupMethod.cs @@ -69,6 +69,15 @@ public override MethodIL EmitIL() } } + MetadataType startup = Context.GetOptionalHelperType("StartupCodeHelpers"); + + // Run module initializers + MethodDesc runModuleInitializers = startup?.GetMethod("RunModuleInitializers", null); + if (runModuleInitializers != null) + { + codeStream.Emit(ILOpcode.call, emitter.NewToken(runModuleInitializers)); + } + codeStream.Emit(ILOpcode.ret); return emitter.Link(this); } From 47dec1829db641b20f8061317ba3dff3ab5eefc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 21 Aug 2025 15:35:38 +0200 Subject: [PATCH 03/11] Cleaner fix if it works --- src/coreclr/nativeaot/Bootstrap/main.cpp | 3 +- .../src/System/Runtime/InternalCalls.cs | 2 +- src/coreclr/nativeaot/Runtime/ICodeManager.h | 2 +- src/coreclr/nativeaot/Runtime/thread.cpp | 39 +++++++++++++++++++ .../src/System/Runtime/RuntimeImports.cs | 12 ++++++ .../System/Threading/Thread.NativeAot.Unix.cs | 4 +- .../Threading/Thread.NativeAot.Windows.cs | 4 +- .../tools/aot/ILCompiler/repro/Program.cs | 15 ++++--- 8 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 57eb0012666e1b..33c9f9c037bf5f 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -125,6 +125,7 @@ void* PalGetModuleHandleFromPointer(void* pointer); MANAGED_RUNTIME_EXPORT(GetRuntimeException) MANAGED_RUNTIME_EXPORT(RuntimeFailFast) +MANAGED_RUNTIME_EXPORT(ThreadEntryPoint) MANAGED_RUNTIME_EXPORT(AppendExceptionStackFrame) MANAGED_RUNTIME_EXPORT(GetSystemArrayEEType) MANAGED_RUNTIME_EXPORT(OnFirstChanceException) @@ -141,7 +142,7 @@ typedef void (MANAGED_RUNTIME_EXPORT_CALLCONV *pfn)(); static const pfn c_classlibFunctions[] = { &MANAGED_RUNTIME_EXPORT_NAME(GetRuntimeException), &MANAGED_RUNTIME_EXPORT_NAME(RuntimeFailFast), - nullptr, // &UnhandledExceptionHandler, + &MANAGED_RUNTIME_EXPORT_NAME(ThreadEntryPoint), &MANAGED_RUNTIME_EXPORT_NAME(AppendExceptionStackFrame), nullptr, // &CheckStaticClassConstruction, &MANAGED_RUNTIME_EXPORT_NAME(GetSystemArrayEEType), diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs index d7557d654a7217..77acff31afa5e9 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -38,7 +38,7 @@ internal enum ClassLibFunctionId { GetRuntimeException = 0, FailFast = 1, - // UnhandledExceptionHandler = 2, // unused + ThreadEntryPoint = 2, AppendExceptionStackFrame = 3, // unused = 4, GetSystemArrayEEType = 5, diff --git a/src/coreclr/nativeaot/Runtime/ICodeManager.h b/src/coreclr/nativeaot/Runtime/ICodeManager.h index b9e157c5cae41a..081ef729bdc4f8 100644 --- a/src/coreclr/nativeaot/Runtime/ICodeManager.h +++ b/src/coreclr/nativeaot/Runtime/ICodeManager.h @@ -99,7 +99,7 @@ enum class ClasslibFunctionId { GetRuntimeException = 0, FailFast = 1, - UnhandledExceptionHandler = 2, + ThreadEntryPoint = 2, AppendExceptionStackFrame = 3, // unused = 4, GetSystemArrayEEType = 5, diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index 45b88d1cde2def..6a76617235eab8 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -4,6 +4,7 @@ #include "common.h" #include "gcenv.h" #include "gcheaputilities.h" +#include "gchandleutilities.h" #include "CommonTypes.h" #include "CommonMacros.h" @@ -1278,6 +1279,44 @@ FCIMPL0(Object**, RhGetThreadStaticStorage) } FCIMPLEND +#ifdef TARGET_UNIX +#define NEWTHREAD_RETURN_TYPE size_t +#else +#define NEWTHREAD_RETURN_TYPE uint32_t +#endif + +FCIMPL1(NEWTHREAD_RETURN_TYPE, RhThreadEntryPoint, void* pContext) +{ + // We will attach the thread early so that when the managed thread entrypoint + // starts running and performs its reverse p/invoke transition, the thread is + // already attached. + // + // This avoids potential deadlocks with module initializers that may be running + // as part of runtime initialization (in non-EXE scenario) and creating new + // threads. When RhThreadEntryPoint runs, the runtime must already be initialized + // enough to be able to run managed code so we don't need to wait for it to + // finish. + + ThreadStore::AttachCurrentThread(); + + Thread * pThread = ThreadStore::GetCurrentThread(); + pThread->SetDeferredTransitionFrameForNativeHelperThread(); + pThread->DisablePreemptiveMode(); + + Object * pThreadObject = ObjectFromHandle((OBJECTHANDLE)pContext); + MethodTable* pMT = pThreadObject->GetMethodTable(); + + pThread->EnablePreemptiveMode(); + + NEWTHREAD_RETURN_TYPE (*pFn)(void*) = (NEWTHREAD_RETURN_TYPE (*)(void*)) + pMT->GetTypeManagerPtr() + ->AsTypeManager() + ->GetClasslibFunction(ClasslibFunctionId::ThreadEntryPoint); + + return pFn(pContext); +} +FCIMPLEND + InlinedThreadStaticRoot* Thread::GetInlinedThreadStaticList() { return m_pInlinedThreadLocalStatics; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 72a238b0bddde2..b2dbcaae2f263b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -26,6 +26,18 @@ internal static partial class RuntimeImports { internal const string RuntimeLibrary = "*"; + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "RhThreadEntryPoint")] +#if TARGET_UNIX + private static extern unsafe nint RhThreadEntryPoint(nint pContext); + internal static unsafe delegate* unmanaged RhGetThreadEntryPointAddress() + => (delegate* unmanaged)(delegate*)&RhThreadEntryPoint; +#else + private static extern unsafe uint RhThreadEntryPoint(nint pContext); + internal static unsafe delegate* unmanaged RhGetThreadEntryPointAddress() + => (delegate* unmanaged)(delegate*)&RhThreadEntryPoint; +#endif + [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhGetCrashInfoBuffer")] internal static extern unsafe byte* RhGetCrashInfoBuffer(out int cbMaxSize); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs index de77bc91b088e3..b30ffd62b08d9a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs @@ -101,7 +101,7 @@ private unsafe bool CreateThread(GCHandle thisThreadHandle) stackSize = RuntimeImports.RhGetDefaultStackSize(); } - if (!Interop.Sys.CreateThread(stackSize, &ThreadEntryPoint, GCHandle.ToIntPtr(thisThreadHandle))) + if (!Interop.Sys.CreateThread(stackSize, RuntimeImports.RhGetThreadEntryPointAddress(), GCHandle.ToIntPtr(thisThreadHandle))) { return false; } @@ -115,7 +115,7 @@ private unsafe bool CreateThread(GCHandle thisThreadHandle) /// /// This is an entry point for managed threads created by application /// - [UnmanagedCallersOnly] + [UnmanagedCallersOnly(EntryPoint = "ThreadEntryPoint")] private static IntPtr ThreadEntryPoint(IntPtr parameter) { StartThread(parameter); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs index f01fe0f86f38f7..37d6d14ab60f4e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs @@ -200,7 +200,7 @@ private unsafe bool CreateThread(GCHandle thisThreadHandle) } _osHandle = Interop.Kernel32.CreateThread(IntPtr.Zero, (IntPtr)stackSize, - &ThreadEntryPoint, GCHandle.ToIntPtr(thisThreadHandle), + RuntimeImports.RhGetThreadEntryPointAddress(), GCHandle.ToIntPtr(thisThreadHandle), Interop.Kernel32.CREATE_SUSPENDED | Interop.Kernel32.STACK_SIZE_PARAM_IS_A_RESERVATION, out _); @@ -219,7 +219,7 @@ private unsafe bool CreateThread(GCHandle thisThreadHandle) /// /// This is an entry point for managed threads created by application /// - [UnmanagedCallersOnly] + [UnmanagedCallersOnly(EntryPoint = "ThreadEntryPoint")] private static uint ThreadEntryPoint(IntPtr parameter) { StartThread(parameter); diff --git a/src/coreclr/tools/aot/ILCompiler/repro/Program.cs b/src/coreclr/tools/aot/ILCompiler/repro/Program.cs index 9e71394c3732a5..42b388c8f7032a 100644 --- a/src/coreclr/tools/aot/ILCompiler/repro/Program.cs +++ b/src/coreclr/tools/aot/ILCompiler/repro/Program.cs @@ -2,11 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; -class Program +Console.WriteLine(Program.x[0]); + +partial class Program { - static void Main() - { - Console.WriteLine("Hello world"); - } + public static readonly byte[] x = "utf8 literal"u8.ToArray(); + + } From ac5ddfa874361d7f76e902cef13a9ed6896febd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 21 Aug 2025 15:38:50 +0200 Subject: [PATCH 04/11] Not this --- src/coreclr/tools/aot/ILCompiler/repro/Program.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler/repro/Program.cs b/src/coreclr/tools/aot/ILCompiler/repro/Program.cs index 42b388c8f7032a..9e71394c3732a5 100644 --- a/src/coreclr/tools/aot/ILCompiler/repro/Program.cs +++ b/src/coreclr/tools/aot/ILCompiler/repro/Program.cs @@ -2,16 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -Console.WriteLine(Program.x[0]); - -partial class Program +class Program { - public static readonly byte[] x = "utf8 literal"u8.ToArray(); - - + static void Main() + { + Console.WriteLine("Hello world"); + } } From 7849c354083164fbfc37d9a08584b4cf3fd23a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 00:04:48 +0200 Subject: [PATCH 05/11] FB --- src/coreclr/nativeaot/Runtime/thread.cpp | 7 ++++++- .../src/System/Runtime/RuntimeImports.cs | 10 +++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index 6a76617235eab8..7c530e555274b6 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -1285,7 +1285,7 @@ FCIMPLEND #define NEWTHREAD_RETURN_TYPE uint32_t #endif -FCIMPL1(NEWTHREAD_RETURN_TYPE, RhThreadEntryPoint, void* pContext) +EXTERN_C STDCALL NEWTHREAD_RETURN_TYPE RhThreadEntryPoint(void* pContext) { // We will attach the thread early so that when the managed thread entrypoint // starts running and performs its reverse p/invoke transition, the thread is @@ -1315,6 +1315,11 @@ FCIMPL1(NEWTHREAD_RETURN_TYPE, RhThreadEntryPoint, void* pContext) return pFn(pContext); } + +FCIMPL0(void*, RhGetThreadEntryPointAddress) +{ + return &RhThreadEntryPoint; +} FCIMPLEND InlinedThreadStaticRoot* Thread::GetInlinedThreadStaticList() diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index b2dbcaae2f263b..59ba6211e0b814 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -27,15 +27,11 @@ internal static partial class RuntimeImports internal const string RuntimeLibrary = "*"; [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "RhThreadEntryPoint")] + [RuntimeImport(RuntimeLibrary, "RhGetThreadEntryPointAddress")] #if TARGET_UNIX - private static extern unsafe nint RhThreadEntryPoint(nint pContext); - internal static unsafe delegate* unmanaged RhGetThreadEntryPointAddress() - => (delegate* unmanaged)(delegate*)&RhThreadEntryPoint; + internal static extern unsafe delegate* unmanaged RhGetThreadEntryPointAddress(); #else - private static extern unsafe uint RhThreadEntryPoint(nint pContext); - internal static unsafe delegate* unmanaged RhGetThreadEntryPointAddress() - => (delegate* unmanaged)(delegate*)&RhThreadEntryPoint; + internal static extern unsafe delegate* unmanaged RhGetThreadEntryPointAddress(); #endif [MethodImplAttribute(MethodImplOptions.InternalCall)] From 56079d3766cb47ef2d1096d5fcc66dcbeaa10d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 00:28:21 +0200 Subject: [PATCH 06/11] Update thread.cpp --- src/coreclr/nativeaot/Runtime/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index 7c530e555274b6..ddf59319724546 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -1318,7 +1318,7 @@ EXTERN_C STDCALL NEWTHREAD_RETURN_TYPE RhThreadEntryPoint(void* pContext) FCIMPL0(void*, RhGetThreadEntryPointAddress) { - return &RhThreadEntryPoint; + return (void*)&RhThreadEntryPoint; } FCIMPLEND From 09be79f2ae9294b117b4453db1c25b6b3a01db4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 00:30:42 +0200 Subject: [PATCH 07/11] Update src/coreclr/nativeaot/Runtime/thread.cpp Co-authored-by: Jan Kotas --- src/coreclr/nativeaot/Runtime/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index ddf59319724546..f0e369224a20ad 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -1285,7 +1285,7 @@ FCIMPLEND #define NEWTHREAD_RETURN_TYPE uint32_t #endif -EXTERN_C STDCALL NEWTHREAD_RETURN_TYPE RhThreadEntryPoint(void* pContext) +static NEWTHREAD_RETURN_TYPE RhThreadEntryPoint(void* pContext) { // We will attach the thread early so that when the managed thread entrypoint // starts running and performs its reverse p/invoke transition, the thread is From 95b426d6355c291d3ff434d069c70106caca20a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 02:42:25 -0700 Subject: [PATCH 08/11] Update main.cpp --- src/coreclr/nativeaot/Bootstrap/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 33c9f9c037bf5f..db97447cfb60c8 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -139,10 +139,12 @@ MANAGED_RUNTIME_EXPORT(ObjectiveCMarshalGetUnhandledExceptionPropagationHandler) typedef void (MANAGED_RUNTIME_EXPORT_CALLCONV *pfn)(); +extern "C" void ThreadEntryPoint(); + static const pfn c_classlibFunctions[] = { &MANAGED_RUNTIME_EXPORT_NAME(GetRuntimeException), &MANAGED_RUNTIME_EXPORT_NAME(RuntimeFailFast), - &MANAGED_RUNTIME_EXPORT_NAME(ThreadEntryPoint), + (pfn)&ThreadEntryPoint, &MANAGED_RUNTIME_EXPORT_NAME(AppendExceptionStackFrame), nullptr, // &CheckStaticClassConstruction, &MANAGED_RUNTIME_EXPORT_NAME(GetSystemArrayEEType), From 6e45d68224469c8403aa7f3f0a3f88055aae6a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 03:28:56 -0700 Subject: [PATCH 09/11] Update main.cpp --- src/coreclr/nativeaot/Bootstrap/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index db97447cfb60c8..4e19753f354942 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -125,7 +125,6 @@ void* PalGetModuleHandleFromPointer(void* pointer); MANAGED_RUNTIME_EXPORT(GetRuntimeException) MANAGED_RUNTIME_EXPORT(RuntimeFailFast) -MANAGED_RUNTIME_EXPORT(ThreadEntryPoint) MANAGED_RUNTIME_EXPORT(AppendExceptionStackFrame) MANAGED_RUNTIME_EXPORT(GetSystemArrayEEType) MANAGED_RUNTIME_EXPORT(OnFirstChanceException) From 328bce7973c7b686e737fc6187005bec0da00176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 13:46:03 -0700 Subject: [PATCH 10/11] Update ThreadEntryPoint signature for platform compatibility --- src/coreclr/nativeaot/Bootstrap/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 4e19753f354942..07eebac6d6d152 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -138,7 +138,11 @@ MANAGED_RUNTIME_EXPORT(ObjectiveCMarshalGetUnhandledExceptionPropagationHandler) typedef void (MANAGED_RUNTIME_EXPORT_CALLCONV *pfn)(); -extern "C" void ThreadEntryPoint(); +#if defined(_WIN32) +extern "C" int ThreadEntryPoint(void* pContext); +#else +extern "C" size_t ThreadEntryPoint(void* pContext); +#endif static const pfn c_classlibFunctions[] = { &MANAGED_RUNTIME_EXPORT_NAME(GetRuntimeException), From 817759bc99288c54da365c41924155b1e95b57d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 22 Aug 2025 14:01:38 -0700 Subject: [PATCH 11/11] Update main.cpp --- src/coreclr/nativeaot/Bootstrap/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 07eebac6d6d152..0fc322e2ee666c 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include +#include #if defined(DEBUG) && defined(_WIN32) #include