From 06651ee97fc13848c425982b2392f1a5c2dec4fd Mon Sep 17 00:00:00 2001 From: Vladimir Sadov Date: Wed, 21 May 2025 07:09:44 -0700 Subject: [PATCH 1/2] Move FLS init before EventPipeAdapter::FinishInitialize and the first SetupThread() (#115546) * fix * PR feedback Co-authored-by: Jan Kotas * moved profiler init before FinalizerThreadCreate * Update src/coreclr/vm/ceemain.cpp Co-authored-by: Jan Kotas * create finalizer thread earlier only on Windows. * Update src/coreclr/vm/ceemain.cpp Co-authored-by: Jan Kotas --------- Co-authored-by: Jan Kotas --- src/coreclr/vm/ceemain.cpp | 58 +++++++++++++++++++++++++----- src/coreclr/vm/finalizerthread.cpp | 1 + src/coreclr/vm/syncblk.cpp | 7 ---- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 4143d763fbca04..5f84b1e0ab974f 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -862,6 +862,7 @@ void EEStartupHelper() #ifdef PROFILING_SUPPORTED // Initialize the profiling services. + // This must happen before Thread::HasStarted() that fires profiler notifications is called on the finalizer thread. hr = ProfilingAPIUtility::InitializeProfiling(); _ASSERTE(SUCCEEDED(hr)); @@ -891,7 +892,12 @@ void EEStartupHelper() // This isn't done as part of InitializeGarbageCollector() above because // debugger must be initialized before creating EE thread objects +#ifdef TARGET_WINDOWS + // Create the finalizer thread on windows earlier, as we will need to wait for + // the completion of its initialization part that initializes COM as that has to be done + // before the first Thread is attached. Thus we want to give the thread a bit more time. FinalizerThread::FinalizerThreadCreate(); +#endif InitPreStubManager(); @@ -906,8 +912,6 @@ void EEStartupHelper() InitJITHelpers1(); InitJITHelpers2(); - SyncBlockCache::Attach(); - // Set up the sync block SyncBlockCache::Start(); @@ -922,6 +926,48 @@ void EEStartupHelper() IfFailGo(hr); + InitializeExceptionHandling(); + + // + // Install our global exception filter + // + if (!InstallUnhandledExceptionFilter()) + { + IfFailGo(E_FAIL); + } + +#ifdef TARGET_WINDOWS + // g_pGCHeap->Initialize() above could take nontrivial time, so by now the finalizer thread + // should have initialized FLS slot for thread cleanup notifications. + // And ensured that COM is initialized (must happen before allocating FLS slot). + // Make sure that this was done before we start creating Thread objects + // Ex: The call to SetupThread below will create and attach a Thread object. + // Event pipe might also do that. + FinalizerThread::WaitForFinalizerThreadStart(); +#endif + + // throws on error + _ASSERTE(GetThreadNULLOk() == NULL); + SetupThread(); + +#ifdef DEBUGGING_SUPPORTED + // Notify debugger once the first thread is created to finish initialization. + if (g_pDebugInterface != NULL) + { + g_pDebugInterface->StartupPhase2(GetThread()); + } +#endif + +#ifndef TARGET_WINDOWS + // This isn't done as part of InitializeGarbageCollector() above because + // debugger must be initialized before creating EE thread objects + FinalizerThread::FinalizerThreadCreate(); +#else + // On windows the finalizer thread is already partially created and is waiting + // right before doing HasStarted(). We will release it now. + FinalizerThread::EnableFinalization(); +#endif + #ifdef FEATURE_PERFTRACING // Finish setting up rest of EventPipe - specifically enable SampleProfiler if it was requested at startup. // SampleProfiler needs to cooperate with the GC which hasn't fully finished setting up in the first part of the @@ -982,12 +1028,6 @@ void EEStartupHelper() g_MiniMetaDataBuffMaxSize, MEM_COMMIT, PAGE_READWRITE); #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS -#ifdef TARGET_WINDOWS - // By now finalizer thread should have initialized FLS slot for thread cleanup notifications. - // And ensured that COM is initialized (must happen before allocating FLS slot). - // Make sure that this was done. - FinalizerThread::WaitForFinalizerThreadStart(); -#endif g_fEEStarted = TRUE; g_EEStartupStatus = S_OK; hr = S_OK; @@ -1794,6 +1834,8 @@ void InitFlsSlot() // thread - thread to attach static void OsAttachThread(void* thread) { + _ASSERTE(g_flsIndex != FLS_OUT_OF_INDEXES); + if (t_flsState == FLS_STATE_INVOKED) { _ASSERTE_ALL_BUILDS(!"Attempt to execute managed code after the .NET runtime thread state has been destroyed."); diff --git a/src/coreclr/vm/finalizerthread.cpp b/src/coreclr/vm/finalizerthread.cpp index 546a8d1eba240f..ef666c863eed2e 100644 --- a/src/coreclr/vm/finalizerthread.cpp +++ b/src/coreclr/vm/finalizerthread.cpp @@ -445,6 +445,7 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args) // handshake with EE initialization, as now we can attach Thread objects to native threads. hEventFinalizerDone->Set(); + WaitForFinalizerEvent (hEventFinalizer); #endif s_FinalizerThreadOK = GetFinalizerThread()->HasStarted(); diff --git a/src/coreclr/vm/syncblk.cpp b/src/coreclr/vm/syncblk.cpp index 868fffca0c0552..4186bccd8846a9 100644 --- a/src/coreclr/vm/syncblk.cpp +++ b/src/coreclr/vm/syncblk.cpp @@ -625,13 +625,6 @@ void SyncBlockCache::CleanupSyncBlocks() } EE_END_FINALLY; } -// create the sync block cache -/* static */ -void SyncBlockCache::Attach() -{ - LIMITED_METHOD_CONTRACT; -} - // create the sync block cache /* static */ void SyncBlockCache::Start() From 8fa74112b7dd669628141fe23095ffe16a2c8921 Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:08:13 -0700 Subject: [PATCH 2/2] Fix merge conflict --- src/coreclr/vm/ceemain.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 5f84b1e0ab974f..3df24664ff2df5 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -869,29 +869,6 @@ void EEStartupHelper() IfFailGo(hr); #endif // PROFILING_SUPPORTED - InitializeExceptionHandling(); - - // - // Install our global exception filter - // - if (!InstallUnhandledExceptionFilter()) - { - IfFailGo(E_FAIL); - } - - // throws on error - SetupThread(); - -#ifdef DEBUGGING_SUPPORTED - // Notify debugger once the first thread is created to finish initialization. - if (g_pDebugInterface != NULL) - { - g_pDebugInterface->StartupPhase2(GetThread()); - } -#endif - - // This isn't done as part of InitializeGarbageCollector() above because - // debugger must be initialized before creating EE thread objects #ifdef TARGET_WINDOWS // Create the finalizer thread on windows earlier, as we will need to wait for // the completion of its initialization part that initializes COM as that has to be done