Skip to content

Commit dd6d28c

Browse files
committed
Continuously track active dispatched exceptions and flares sent
1 parent 367c638 commit dd6d28c

File tree

5 files changed

+96
-161
lines changed

5 files changed

+96
-161
lines changed

src/coreclr/debug/di/process.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,8 @@ void CordbProcess::Neuter()
13411341
}
13421342
m_unmanagedThreadHashTable.RemoveAll();
13431343
m_dwOutOfProcessStepping = 0;
1344+
m_cProcessedFlares = 0;
1345+
m_fDetachInProgress = FALSE;
13441346
#endif
13451347

13461348
NeuterChildren();
@@ -3131,7 +3133,6 @@ void CordbProcess::DetachShim()
31313133
DetachInProgressGuard(CordbProcess * pProcess)
31323134
{
31333135
m_pProcess = pProcess;
3134-
pProcess->m_cProcessedFlares = 0;
31353136
pProcess->m_fDetachInProgress = TRUE;
31363137
}
31373138
~DetachInProgressGuard()

src/coreclr/debug/di/rspriv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3324,11 +3324,11 @@ class CordbProcess :
33243324
DetachNotifications(CordbProcess * process) : m_process(process) { }
33253325
~DetachNotifications()
33263326
{
3327+
DWORD dwProcessedFlares = InterlockedIncrement(&m_process->m_cProcessedFlares);
33273328
if (m_process->m_fDetachInProgress)
33283329
{
33293330
// notify that there has been an update to the number of processed
33303331
// SetThreadContextNeeded events
3331-
DWORD dwProcessedFlares = InterlockedIncrement(&m_process->m_cProcessedFlares);
33323332
LOG((LF_CORDB, LL_INFO10000, "HSTCN: Detach in progress - %d\n", dwProcessedFlares));
33333333
SetEvent(m_process->m_detachSetThreadContextNeededEvent);
33343334
}

src/coreclr/debug/ee/controller.cpp

Lines changed: 69 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,16 +1121,6 @@ DebuggerController::DebuggerController(Thread * pThread, AppDomain * pAppDomain)
11211121
{
11221122
m_next = g_controllers;
11231123
g_controllers = this;
1124-
1125-
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
1126-
if (DebuggerController::GetProcessingDetach())
1127-
{
1128-
// If we are detaching, we need to increment the active dispatched exceptions
1129-
// so that we can send the detach complete message when we are done.
1130-
int cActiveDispatchedExceptions = DebuggerController::IncrementActiveDispatchedExceptions();
1131-
LOG((LF_CORDB, LL_INFO10000, "DC::DC %p incrementing ActiveDispatchedExceptions=%d\n", this, cActiveDispatchedExceptions));
1132-
}
1133-
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
11341124
}
11351125
}
11361126

@@ -1207,20 +1197,14 @@ DebuggerController::~DebuggerController()
12071197
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
12081198
if (DebuggerController::GetProcessingDetach())
12091199
{
1210-
int cActiveDispatchedExceptions = DebuggerController::DecrementActiveDispatchedExceptions();
1211-
LOG((LF_CORDB, LL_INFO10000, "DC::~DC %p decrementing ActiveDispatchedExceptions=%d\n", this, cActiveDispatchedExceptions));
1212-
1213-
if (cActiveDispatchedExceptions == 0)
1214-
{
1215-
DebuggerController::SetProcessingDetach(FALSE);
1216-
sendDetachComplete = true;
1217-
}
1200+
sendDetachComplete = CanSendDetach();
12181201
}
12191202
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
12201203
}
12211204
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
12221205
if (sendDetachComplete && g_pDebugger != NULL)
12231206
{
1207+
LOG((LF_CORDB, LL_INFO1000, "DC::~DC: Sending DetachComplete\n"));
12241208
g_pDebugger->SendDetachComplete();
12251209
}
12261210
#endif
@@ -3095,15 +3079,6 @@ DPOSS_ACTION DebuggerController::DispatchPatchOrSingleStep(Thread *thread, CONTE
30953079
}
30963080
_ASSERTE(g_patches != NULL);
30973081

3098-
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
3099-
{
3100-
int cDispatchedExceptions = DebuggerController::IncrementActiveDispatchedExceptions();
3101-
LOG((LF_CORDB|LF_ENC, LL_INFO10000, "DC::DPOSS Incremented Exception Count = %d\n", cDispatchedExceptions));
3102-
}
3103-
3104-
bool isProcessingDetach = DebuggerController::GetProcessingDetach();
3105-
#endif
3106-
31073082
CrstHolderWithState lockController(&g_criticalSection);
31083083

31093084
TADDR originalAddress = 0;
@@ -3169,15 +3144,6 @@ DPOSS_ACTION DebuggerController::DispatchPatchOrSingleStep(Thread *thread, CONTE
31693144
address = (CORDB_ADDRESS_TYPE *)(UINT_PTR)0xAABBCCFF;
31703145
#endif //_DEBUG
31713146

3172-
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
3173-
if (DebuggerController::GetProcessingDetach() && IsInUsedAction(used))
3174-
{
3175-
int cDispatchedFlares = DebuggerController::IncrementDispatchedFlares();
3176-
isProcessingDetach = true;
3177-
LOG((LF_CORDB|LF_ENC, LL_INFO10000, "DC::DPOSS Incremented Flare Count = %d\n", cDispatchedFlares));
3178-
}
3179-
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
3180-
31813147
if (dcq.dcqGetCount()> 0)
31823148
{
31833149
lockController.Release();
@@ -3278,14 +3244,6 @@ DPOSS_ACTION DebuggerController::DispatchPatchOrSingleStep(Thread *thread, CONTE
32783244

32793245
lockController.Release();
32803246

3281-
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
3282-
if (DebuggerController::GetProcessingDetach() && IsInUsedAction(used) && !isProcessingDetach)
3283-
{
3284-
int cDispatchedFlares = DebuggerController::IncrementDispatchedFlares();
3285-
isProcessingDetach = true;
3286-
LOG((LF_CORDB|LF_ENC, LL_INFO10000, "DC::DPOSS Incremented Flare Count = %d\n", cDispatchedFlares));
3287-
}
3288-
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
32893247

32903248
// We pulse the GC mode here too cooperate w/ a thread trying to suspend the runtime. If we didn't pulse
32913249
// the GC, the odds of catching this thread in interruptible code may be very small (since this filter
@@ -3312,43 +3270,6 @@ DPOSS_ACTION DebuggerController::DispatchPatchOrSingleStep(Thread *thread, CONTE
33123270

33133271
}
33143272

3315-
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
3316-
if (DebuggerController::GetProcessingDetach() && IsInUsedAction(used) && !isProcessingDetach)
3317-
{
3318-
int cDispatchedFlares = DebuggerController::IncrementDispatchedFlares();
3319-
isProcessingDetach = true;
3320-
LOG((LF_CORDB|LF_ENC, LL_INFO10000, "DC::DPOSS Incremented Flare Count = %d\n", cDispatchedFlares));
3321-
}
3322-
3323-
if (DebuggerController::GetProcessingDetach())
3324-
{
3325-
lockController.Acquire();
3326-
3327-
int cDispatchedExceptions = DebuggerController::DecrementActiveDispatchedExceptions();
3328-
LOG((LF_CORDB|LF_ENC, LL_INFO10000, "DC::DPOSS Decrement Exception Count = %d\n", cDispatchedExceptions));
3329-
3330-
int cDispatchedFlares = DebuggerController::GetDispatchedFlares();
3331-
_ASSERTE(cDispatchedFlares >= 0);
3332-
_ASSERTE(cDispatchedExceptions >= 0);
3333-
3334-
if (cDispatchedExceptions == 0)
3335-
{
3336-
DebuggerController::SetProcessingDetach(FALSE);
3337-
lockController.Release();
3338-
3339-
if (g_pDebugger != NULL)
3340-
{
3341-
g_pDebugger->SendDetachComplete();
3342-
}
3343-
}
3344-
}
3345-
else
3346-
{
3347-
int cDispatchedExceptions = DebuggerController::DecrementActiveDispatchedExceptions();
3348-
LOG((LF_CORDB|LF_ENC, LL_INFO10000, "DC::DPOSS Decrement Exception Count = %d\n", cDispatchedExceptions));
3349-
}
3350-
#endif
3351-
33523273
RETURN used;
33533274
}
33543275

@@ -4463,26 +4384,43 @@ void DebuggerController::TriggerExternalMethodFixup(PCODE target)
44634384
}
44644385

44654386
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
4466-
/*static*/ int DebuggerController::GetNumPendingControllers()
4387+
bool DebuggerController::CanSendDetach(bool fDecrementActiveExceptions)
44674388
{
4468-
CONTRACTL
4469-
{
4470-
NOTHROW;
4471-
GC_NOTRIGGER;
4472-
}
4473-
CONTRACTL_END;
4474-
4475-
ControllerLockHolder lockController;
4476-
int cTotalPendingControllers = 0;
4477-
4478-
for (DebuggerController* p = g_controllers; p != NULL; p = p->m_next)
4389+
bool fCanSendDetach = g_pDebugInterface == NULL || !g_pDebugInterface->IsOutOfProcessSetContextEnabled();
4390+
if (!fCanSendDetach)
44794391
{
4480-
cTotalPendingControllers++;
4392+
ControllerLockHolder lockController;
4393+
bool fHasControllers = (g_controllers != NULL);
4394+
int cActiveDispatchedExceptions = fDecrementActiveExceptions ? DebuggerController::DecrementActiveDispatchedExceptions() : DebuggerController::GetActiveDispatchedExceptions();
4395+
#ifdef _DEBUG
4396+
if (fDecrementActiveExceptions)
4397+
{
4398+
LOG((LF_CORDB, LL_INFO10000, "DC::CSD --active dispatched exceptions count = %d, HasControllers = %d\n", cActiveDispatchedExceptions, fHasControllers));
4399+
}
4400+
else
4401+
{
4402+
LOG((LF_CORDB, LL_INFO10000, "DC::CSD active dispatched exceptions count = %d, HasControllers = %d\n", cActiveDispatchedExceptions, fHasControllers));
4403+
}
4404+
#endif
4405+
if (!fHasControllers && cActiveDispatchedExceptions == 0)
4406+
{
4407+
// No outstanding controllers or active dispatched exceptions, so it is safe to detach
4408+
DebuggerController::SetProcessingDetach(FALSE);
4409+
fCanSendDetach = true;
4410+
LOG((LF_CORDB, LL_INFO10000, "DC::CSD Can Detach\n"));
4411+
}
4412+
else if (!DebuggerController::GetProcessingDetach())
4413+
{
4414+
// this will cause DC::DNE to respond to this IPC once the queue of pending controllers has been processed
4415+
DebuggerController::SetProcessingDetach(TRUE);
4416+
fCanSendDetach = false;
4417+
LOG((LF_CORDB, LL_INFO10000, "DC::CSD Unable to Detach, need to drain existing controllers or exception processing\n"));
4418+
}
44814419
}
44824420

4483-
return cTotalPendingControllers;
4421+
return fCanSendDetach;
44844422
}
4485-
#endif
4423+
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
44864424

44874425
#ifdef _DEBUG
44884426
// See comment in DispatchNativeException
@@ -4583,16 +4521,6 @@ bool DebuggerController::DispatchNativeException(EXCEPTION_RECORD *pException,
45834521
return FALSE;
45844522
}
45854523

4586-
// It's possible we're here without a debugger (since we have to call the
4587-
// patch skippers). The Debugger may detach anytime,
4588-
// so remember the attach state now.
4589-
#ifdef _DEBUG
4590-
bool fWasAttached = false;
4591-
#ifdef DEBUGGING_SUPPORTED
4592-
fWasAttached = (CORDebuggerAttached() != 0);
4593-
#endif //DEBUGGING_SUPPORTED
4594-
#endif //_DEBUG
4595-
45964524
{
45974525
// If we're in cooperative mode, it's unsafe to do a GC until we've put a filter context in place.
45984526
GCX_NOTRIGGER();
@@ -4632,6 +4560,15 @@ bool DebuggerController::DispatchNativeException(EXCEPTION_RECORD *pException,
46324560
// Otherwise it is an error to nest at all
46334561
_ASSERTE(pOldContext == NULL);
46344562

4563+
4564+
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
4565+
if (g_pDebugInterface != NULL && g_pDebugInterface->IsOutOfProcessSetContextEnabled())
4566+
{
4567+
int cActiveDispatchedExceptions = DebuggerController::IncrementActiveDispatchedExceptions();
4568+
LOG((LF_CORDB, LL_INFO10000, "DC::DNE ++active dispatched exceptions count = %d\n", cActiveDispatchedExceptions));
4569+
}
4570+
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
4571+
46354572
fDispatch = DebuggerController::DispatchExceptionHook(pCurThread,
46364573
pContext,
46374574
pException);
@@ -4695,13 +4632,6 @@ bool DebuggerController::DispatchNativeException(EXCEPTION_RECORD *pException,
46954632
#endif
46964633
);
46974634
LOG((LF_CORDB, LL_EVERYTHING, "DC::DNE DispatchPatch call returned\n"));
4698-
4699-
// If we detached, we should remove all our breakpoints. So if we try
4700-
// to handle this breakpoint, make sure that we're attached.
4701-
if (IsInUsedAction(result) == true)
4702-
{
4703-
_ASSERTE(fWasAttached);
4704-
}
47054635
break;
47064636

47074637
case EXCEPTION_SINGLE_STEP:
@@ -4759,6 +4689,31 @@ bool DebuggerController::DispatchNativeException(EXCEPTION_RECORD *pException,
47594689
pCurThread->ApplySingleStep(pContext);
47604690
#endif // FEATURE_EMULATE_SINGLESTEP
47614691

4692+
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
4693+
{
4694+
if (fDebuggers && g_pDebugInterface != NULL && g_pDebugInterface->IsOutOfProcessSetContextEnabled())
4695+
{
4696+
int cDispatchedFlares = DebuggerController::IncrementDispatchedFlares();
4697+
LOG((LF_CORDB, LL_INFO10000, "DC::DNE ++dispatched flare count = %d\n", cDispatchedFlares));
4698+
}
4699+
4700+
if (DebuggerController::GetProcessingDetach())
4701+
{
4702+
LOG((LF_CORDB, LL_INFO10000, "DC::DNE, Processing Detach: calling CanSendDetach...\n"));
4703+
if (DebuggerController::CanSendDetach(true) && g_pDebugger != NULL)
4704+
{
4705+
LOG((LF_CORDB, LL_INFO10000, "DC::DNE, Detaching...\n"));
4706+
g_pDebugger->SendDetachComplete();
4707+
}
4708+
}
4709+
else if (g_pDebugInterface != NULL && g_pDebugInterface->IsOutOfProcessSetContextEnabled())
4710+
{
4711+
int cActiveDispatchedExceptions = DebuggerController::DecrementActiveDispatchedExceptions();
4712+
LOG((LF_CORDB, LL_INFO10000, "DC::DNE, NOT processing Detach, --active dispatched exceptions: %d\n", cActiveDispatchedExceptions));
4713+
}
4714+
}
4715+
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
4716+
47624717
FireEtwDebugExceptionProcessingEnd();
47634718

47644719
return fDebuggers;
@@ -4916,7 +4871,7 @@ bool DebuggerPatchSkip::DebuggerDetachClean()
49164871

49174872
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
49184873
// during detach we need to ensure the context is only being updated out of process
4919-
bool bUsingOutOfProcEvents = g_pDebugInterface->IsOutOfProcessSetContextEnabled();
4874+
bool bUsingOutOfProcEvents = g_pDebugInterface != NULL && g_pDebugInterface->IsOutOfProcessSetContextEnabled();
49204875
if (bUsingOutOfProcEvents)
49214876
{
49224877
return false; // return false so that we do not delete this controller

src/coreclr/debug/ee/controller.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,13 +1161,14 @@ class DebuggerController
11611161
static bool GetProcessingDetach() {LIMITED_METHOD_CONTRACT; return g_fProcessingDetach; }
11621162
static void SetProcessingDetach(bool fProcessingDetach) {LIMITED_METHOD_CONTRACT; g_fProcessingDetach = fProcessingDetach; }
11631163
static int GetActiveDispatchedExceptions() {LIMITED_METHOD_CONTRACT; return g_cActiveDispatchedExceptions; }
1164-
static void IncrementActiveDispatchedExceptions(int cActiveDispatchedExceptions) { LIMITED_METHOD_CONTRACT; g_cActiveDispatchedExceptions += cActiveDispatchedExceptions; }
11651164
static int IncrementActiveDispatchedExceptions() { LIMITED_METHOD_CONTRACT; return (int)InterlockedIncrement(&g_cActiveDispatchedExceptions); }
11661165
static int DecrementActiveDispatchedExceptions() { LIMITED_METHOD_CONTRACT; return (int)InterlockedDecrement(&g_cActiveDispatchedExceptions); }
1167-
static int GetNumPendingControllers();
11681166
static int GetDispatchedFlares() {LIMITED_METHOD_DAC_CONTRACT; return g_cDispatchedFlares; }
1169-
static void SetDispatchedFlares(int cDispatchedFlares) { LIMITED_METHOD_DAC_CONTRACT; g_cDispatchedFlares = cDispatchedFlares; }
11701167
static int IncrementDispatchedFlares() { LIMITED_METHOD_DAC_CONTRACT; return (int)InterlockedIncrement(&g_cDispatchedFlares); }
1168+
static void ResetDispatchedFlares() { LIMITED_METHOD_DAC_CONTRACT; g_cDispatchedFlares = 0; }
1169+
static bool CanSendDetach(bool fDecrementActiveExceptions = false);
1170+
#else
1171+
static int GetDispatchedFlares() {LIMITED_METHOD_DAC_CONTRACT; return 0; }
11711172
#endif
11721173

11731174
#if defined(_DEBUG)
@@ -1224,23 +1225,19 @@ class DebuggerController
12241225
static int g_cTotalMethodEnter;
12251226

12261227
// When detach is initiated, the runtime is synchronized.
1227-
// This is a running count of dispatched exceptions that
1228-
// could result in a SetThreadContextNeeded event.
1228+
// However, it is possible that DC::DNE is still processing debugger events.
1229+
// This is a running count of exceptions running inside of DC::DNE
12291230
// Detach will use this to get an accurate count of
12301231
// SetThreadContextNeeded flares after continuing.
1231-
// State is tracked globally because the controllers are deleted
1232-
// during the detach operation
1233-
// This variable is only used while the debugger is attached
12341232
static Volatile<DWORD> g_cActiveDispatchedExceptions;
12351233

12361234
// During detach we need to wait until all flares have been processed
12371235
// before allowing the detach to proceed. Once this flag is set
12381236
// true, we will start tracking the number of dispatched flares.
12391237
static Volatile<BOOL> g_fProcessingDetach;
12401238

1241-
// This is the number of flares that have been sent after
1242-
// continuing inside of a detach request
1243-
// This will be sent to the right side to ensure that it stays attached
1239+
// This is the number of flares that have been sent
1240+
// It will be sent to the right side to ensure that it stays attached
12441241
// long enough to process any SetThreadContextNeeded events
12451242
static Volatile<DWORD> g_cDispatchedFlares;
12461243

0 commit comments

Comments
 (0)