From f902c9d4f18c2b1cbc838d41fa39bea627161e4a Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Mon, 21 Sep 2020 12:09:49 -0700 Subject: [PATCH] [5.0] Fix to allow entering cooperative GC mode when the thread is in a forbid-suspend-for-debugger region - Port of https://github.com/dotnet/runtime/pull/42587 to 5.0 - Followup to https://github.com/dotnet/runtime/pull/40060 - In short timing windows if a thread is placed in a pending-suspend-for-debugger state while in a forbid-suspend-for-debugger region, from the above PR it would not suspend for the debugger but it was missed that it can also get stuck in a perpetual spin-wait while entering cooperative GC mode. This causes the thread to not suspend for the debugger (VS times out after waiting) and the thread can only progress by unmarking it for debugger suspension. - Fixed to break the spin-wait by checking whether the thread is in the forbid region Fixes https://github.com/dotnet/runtime/issues/42375 --- src/coreclr/src/vm/threadsuspend.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/coreclr/src/vm/threadsuspend.cpp b/src/coreclr/src/vm/threadsuspend.cpp index 51a2b07dcd79a5..293c65941569c6 100644 --- a/src/coreclr/src/vm/threadsuspend.cpp +++ b/src/coreclr/src/vm/threadsuspend.cpp @@ -2277,8 +2277,9 @@ void Thread::RareDisablePreemptiveGC() // Note IsGCInProgress is also true for say Pause (anywhere SuspendEE happens) and GCThread is the // thread that did the Pause. While in Pause if another thread attempts Rev/Pinvoke it should get inside the following and // block until resume - if ((GCHeapUtilities::IsGCInProgress() && (this != ThreadSuspend::GetSuspensionThread())) || - (m_State & (TS_DebugSuspendPending | TS_StackCrawlNeeded))) + if ((GCHeapUtilities::IsGCInProgress() && (this != ThreadSuspend::GetSuspensionThread())) || + ((m_State & TS_DebugSuspendPending) && !IsInForbidSuspendForDebuggerRegion()) || + (m_State & TS_StackCrawlNeeded)) { STRESS_LOG1(LF_SYNC, LL_INFO1000, "RareDisablePreemptiveGC: entering. Thread state = %x\n", m_State.Load()); @@ -2369,7 +2370,8 @@ void Thread::RareDisablePreemptiveGC() // thread while in this loop. This happens if you use the COM+ // debugger to suspend this thread and then release it. if (! ((GCHeapUtilities::IsGCInProgress() && (this != ThreadSuspend::GetSuspensionThread())) || - (m_State & (TS_DebugSuspendPending | TS_StackCrawlNeeded))) ) + ((m_State & TS_DebugSuspendPending) && !IsInForbidSuspendForDebuggerRegion()) || + (m_State & TS_StackCrawlNeeded)) ) { break; }