m_pLazyData(NULL),
m_defines(_defines),
m_isBlockedOnGarbageCollectionEvent(FALSE),
+ m_willBlockOnGarbageCollectionEvent(FALSE),
m_isGarbageCollectionEventsEnabled(FALSE),
m_isGarbageCollectionEventsEnabledLatch(FALSE)
{
return (m_threadsAtUnsafePlaces != 0);
}
-void Debugger::BeforeGarbageCollection()
+void Debugger::SuspendForGarbageCollectionStarted()
{
CONTRACTL
{
GC_NOTRIGGER;
}
CONTRACTL_END;
-
+
this->m_isGarbageCollectionEventsEnabledLatch = this->m_isGarbageCollectionEventsEnabled;
+ this->m_willBlockOnGarbageCollectionEvent = this->m_isGarbageCollectionEventsEnabledLatch;
+}
+
+void Debugger::SuspendForGarbageCollectionCompleted()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
if (!CORDebuggerAttached() || !this->m_isGarbageCollectionEventsEnabledLatch)
{
return;
}
+ this->m_isBlockedOnGarbageCollectionEvent = TRUE;
Thread* pThread = GetThread();
{
Debugger::DebuggerLockHolder dbgLockHolder(this);
- this->m_isBlockedOnGarbageCollectionEvent = true;
-
DebuggerIPCEvent* ipce1 = m_pRCThread->GetIPCEventSendBuffer();
InitIPCEvent(ipce1,
DB_IPCE_BEFORE_GARBAGE_COLLECTION,
ResetEvent(this->GetGarbageCollectionBlockerEvent());
}
-void Debugger::AfterGarbageCollection()
+void Debugger::ResumeForGarbageCollectionStarted()
{
CONTRACTL
{
WaitForSingleObject(this->GetGarbageCollectionBlockerEvent(), INFINITE);
ResetEvent(this->GetGarbageCollectionBlockerEvent());
- this->m_isBlockedOnGarbageCollectionEvent = false;
+ this->m_isBlockedOnGarbageCollectionEvent = FALSE;
+ this->m_willBlockOnGarbageCollectionEvent = FALSE;
}
#ifdef FEATURE_DATABREAKPOINT
if ((pEvent->type & DB_IPCE_TYPE_MASK) == DB_IPCE_ASYNC_BREAK ||
(pEvent->type & DB_IPCE_TYPE_MASK) == DB_IPCE_ATTACHING ||
- this->m_isBlockedOnGarbageCollectionEvent)
+ this->m_willBlockOnGarbageCollectionEvent)
{
- if (!this->m_isBlockedOnGarbageCollectionEvent)
+ if (!this->m_willBlockOnGarbageCollectionEvent && !this->m_stopped)
{
lockedThreadStore = true;
ThreadSuspend::LockThreadStore(ThreadSuspend::SUSPEND_FOR_DEBUGGER);
_ASSERTE(ThreadHoldsLock());
// Simply trap all Runtime threads if we're not already trying to.
- if (!m_isBlockedOnGarbageCollectionEvent && !m_trappingRuntimeThreads)
+ if (!m_willBlockOnGarbageCollectionEvent && !m_trappingRuntimeThreads)
{
// If the RS sent an Async-break, then that's an explicit request.
m_RSRequestedSync = TRUE;
DWORD m_defines;
DWORD m_mdDataStructureVersion;
#ifndef DACCESS_COMPILE
- virtual void BeforeGarbageCollection();
- virtual void AfterGarbageCollection();
+ virtual void SuspendForGarbageCollectionStarted();
+ virtual void SuspendForGarbageCollectionCompleted();
+ virtual void ResumeForGarbageCollectionStarted();
#endif
BOOL m_isBlockedOnGarbageCollectionEvent;
+ BOOL m_willBlockOnGarbageCollectionEvent;
BOOL m_isGarbageCollectionEventsEnabled;
// this latches m_isGarbageCollectionEventsEnabled in BeforeGarbageCollection so we can
// guarantee the corresponding AfterGC event is sent even if the events are disabled during GC.
_ASSERTE(reason == SUSPEND_FOR_GC || reason == SUSPEND_FOR_GC_PREP);
+ g_pDebugInterface->SuspendForGarbageCollectionStarted();
+
ThreadSuspend::SuspendEE((ThreadSuspend::SUSPEND_REASON)reason);
- g_pDebugInterface->BeforeGarbageCollection();
+ g_pDebugInterface->SuspendForGarbageCollectionCompleted();
}
void GCToEEInterface::RestartEE(bool bFinishedGC)
{
WRAPPER_NO_CONTRACT;
- g_pDebugInterface->AfterGarbageCollection();
+ g_pDebugInterface->ResumeForGarbageCollectionStarted();
ThreadSuspend::RestartEE(bFinishedGC, TRUE);
}