mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-05 08:06:56 +07:00
[debugger] Add proper processing of explicitly resumed threads
GitOrigin-RevId: 85cfa795069482bb32c50f3d35b99238f2f9eb98
This commit is contained in:
committed by
intellij-monorepo-bot
parent
886c4f6bc0
commit
cc17be8830
@@ -778,7 +778,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
|
||||
}
|
||||
boolean noStandardSuspendNeeded;
|
||||
if (DebuggerUtils.isAlwaysSuspendThreadBeforeSwitch()) {
|
||||
noStandardSuspendNeeded = specialSuspendProcessingForAlwaysSwitch(suspendContext, requestor, suspendManager, thread);
|
||||
noStandardSuspendNeeded = specialSuspendProcessingForAlwaysSwitch(suspendContext, requestor, (SuspendManagerImpl)suspendManager, thread);
|
||||
}
|
||||
else {
|
||||
noStandardSuspendNeeded = requestor instanceof CustomProcessingLocatableEventRequestor customRequestor &&
|
||||
@@ -792,7 +792,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
|
||||
|
||||
private static boolean specialSuspendProcessingForAlwaysSwitch(@NotNull SuspendContextImpl suspendContext,
|
||||
@NotNull LocatableEventRequestor requestor,
|
||||
@NotNull SuspendManager suspendManager,
|
||||
@NotNull SuspendManagerImpl suspendManager,
|
||||
@NotNull ThreadReference thread) {
|
||||
if (suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL) {
|
||||
if (!(requestor instanceof SuspendOtherThreadsRequestor)) {
|
||||
@@ -815,15 +815,44 @@ public class DebugProcessEvents extends DebugProcessImpl {
|
||||
afterSwitch = c -> true;
|
||||
}
|
||||
boolean noStandardSuspendNeeded;
|
||||
if (ContainerUtil.exists(suspendManager.getEventContexts(), c -> c.mySuspendAllSwitchedContext)) {
|
||||
List<SuspendContextImpl> suspendAllContexts =
|
||||
ContainerUtil.filter(suspendManager.getEventContexts(), c -> c.getSuspendPolicy() == EventRequest.SUSPEND_ALL);
|
||||
if (!suspendAllContexts.isEmpty()) {
|
||||
if (suspendAllContexts.size() > 1) {
|
||||
LOG.error("Many suspend all switch contexts: " + suspendAllContexts);
|
||||
}
|
||||
|
||||
// Already stopped, so this is "remaining" event. Need to resume the event.
|
||||
noStandardSuspendNeeded = true;
|
||||
if (thread.suspendCount() == 1) {
|
||||
// There are some errors in evaluation-resume-suspend logic
|
||||
LOG.error("This means resuming this thead to the running state");
|
||||
DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
|
||||
ThreadReferenceProxyImpl threadProxy = debugProcess.getVirtualMachineProxy().getThreadReferenceProxy(thread);
|
||||
if (suspendManager.myExplicitlyResumedThreads.contains(threadProxy)) {
|
||||
for (SuspendContextImpl context : suspendManager.getEventContexts()) {
|
||||
if (context.getSuspendPolicy() == EventRequest.SUSPEND_ALL && !context.suspends(threadProxy)) {
|
||||
suspendManager.suspendThread(context, threadProxy);
|
||||
}
|
||||
}
|
||||
suspendManager.myExplicitlyResumedThreads.remove(threadProxy);
|
||||
suspendManager.voteResume(suspendContext);
|
||||
SuspendContextImpl suspendAllContext = suspendAllContexts.get(0);
|
||||
debugProcess.getManagerThread().schedule(new SuspendContextCommandImpl(suspendAllContext) {
|
||||
@Override
|
||||
public void contextAction(@NotNull SuspendContextImpl c) {
|
||||
DebuggerSession session = debugProcess.getSession();
|
||||
DebuggerContextImpl debuggerContext = DebuggerContextImpl.createDebuggerContext(session, suspendAllContext, threadProxy, null);
|
||||
DebuggerInvocationUtil.invokeLater(debugProcess.getProject(),
|
||||
() -> session.getContextManager().setState(debuggerContext, DebuggerSession.State.PAUSED, DebuggerSession.Event.CONTEXT, null));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (thread.suspendCount() == 1) {
|
||||
// There are some errors in evaluation-resume-suspend logic
|
||||
LOG.error("This means resuming this thead to the running state");
|
||||
}
|
||||
suspendManager.voteResume(suspendContext);
|
||||
debugProcess.notifyStoppedOtherThreads();
|
||||
}
|
||||
suspendManager.voteResume(suspendContext);
|
||||
suspendContext.getDebugProcess().notifyStoppedOtherThreads();
|
||||
}
|
||||
else {
|
||||
noStandardSuspendNeeded = SuspendOtherThreadsRequestor.initiateTransferToSuspendAll(suspendContext, afterSwitch);
|
||||
|
||||
@@ -180,7 +180,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
public void paused(@NotNull SuspendContext suspendContext) {
|
||||
boolean isSuspendAll = suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL;
|
||||
if (isSuspendAll && DebuggerUtils.isNewThreadSuspendStateTracking()) {
|
||||
resumeThreadsUnderEvaluationAfterPause((SuspendContextImpl)suspendContext);
|
||||
resumeThreadsUnderEvaluationAndExplicitlyResumedAfterPause((SuspendContextImpl)suspendContext);
|
||||
}
|
||||
|
||||
myThreadBlockedMonitor.stopWatching(!isSuspendAll ? suspendContext.getThread() : null);
|
||||
@@ -1099,7 +1099,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
}
|
||||
|
||||
|
||||
private void resumeThreadsUnderEvaluationAfterPause(@NotNull SuspendContextImpl suspendAllContext) {
|
||||
private void resumeThreadsUnderEvaluationAndExplicitlyResumedAfterPause(@NotNull SuspendContextImpl suspendAllContext) {
|
||||
for (SuspendContextImpl suspendContext : mySuspendManager.getEventContexts()) {
|
||||
EvaluationContextImpl evaluationContext = suspendContext.getEvaluationContext();
|
||||
if (evaluationContext != null) {
|
||||
@@ -1117,6 +1117,17 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
}
|
||||
}
|
||||
}
|
||||
List<ThreadReferenceProxyImpl> threads = new ArrayList<>(mySuspendManager.myExplicitlyResumedThreads);
|
||||
for (ThreadReferenceProxyImpl thread : threads) {
|
||||
if (thread == suspendAllContext.getEventThread()) {
|
||||
// It seems, it is stopped on the breakpoint on this explicitly resumed thread
|
||||
mySuspendManager.myExplicitlyResumedThreads.remove(thread);
|
||||
continue;
|
||||
}
|
||||
if (!suspendAllContext.suspends(thread)) { // the previous loop can theoretically resume it already
|
||||
mySuspendManager.resumeThread(suspendAllContext, thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class InvokeCommand<E extends Value> {
|
||||
@@ -1241,7 +1252,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
}
|
||||
finally {
|
||||
myEvaluationContext.setThreadForEvaluation(null);
|
||||
if (DebuggerUtils.isNewThreadSuspendStateTracking()) {
|
||||
if (DebuggerUtils.isNewThreadSuspendStateTracking() && !mySuspendManager.myExplicitlyResumedThreads.contains(invokeThread)) {
|
||||
for (SuspendContextImpl anotherContext : mySuspendManager.getEventContexts()) {
|
||||
if (anotherContext != suspendContext && !anotherContext.suspends(invokeThread)) {
|
||||
boolean shouldSuspendThread = false;
|
||||
@@ -2143,14 +2154,16 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(getSuspendManager(), myThread);
|
||||
final Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(mySuspendManager, myThread);
|
||||
for (SuspendContextImpl suspendContext : suspendingContexts) {
|
||||
if (suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD && suspendContext.getEventThread() == myThread) {
|
||||
getSession().getXDebugSession().sessionResumed();
|
||||
getManagerThread().invoke(createResumeCommand(suspendContext));
|
||||
}
|
||||
else {
|
||||
getSuspendManager().resumeThread(suspendContext, myThread);
|
||||
DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().removeThreadFilter(context.getDebugProcess());
|
||||
mySuspendManager.resumeThread(suspendContext, myThread);
|
||||
mySuspendManager.myExplicitlyResumedThreads.add(myThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ public class SuspendManagerImpl implements SuspendManager {
|
||||
private final Deque<SuspendContextImpl> myPausedContexts = new ConcurrentLinkedDeque<>();
|
||||
private final Set<ThreadReferenceProxyImpl> myFrozenThreads = ConcurrentCollectionFactory.createConcurrentSet();
|
||||
|
||||
protected final Set<ThreadReferenceProxyImpl> myExplicitlyResumedThreads = ConcurrentCollectionFactory.createConcurrentSet();
|
||||
|
||||
private final DebugProcessImpl myDebugProcess;
|
||||
|
||||
private int suspends = 0;
|
||||
@@ -148,6 +150,13 @@ public class SuspendManagerImpl implements SuspendManager {
|
||||
|
||||
myDebugProcess.logThreads();
|
||||
popContext(context);
|
||||
if (context.getSuspendPolicy() == EventRequest.SUSPEND_ALL) {
|
||||
if (!ContainerUtil.exists(myPausedContexts, c -> c.getSuspendPolicy() == EventRequest.SUSPEND_ALL)) {
|
||||
myExplicitlyResumedThreads.clear();
|
||||
} else if (eventThread != null && !ContainerUtil.exists(myEventContexts, c -> c.suspends(eventThread))) {
|
||||
myExplicitlyResumedThreads.add(eventThread);
|
||||
}
|
||||
}
|
||||
Set<ThreadReferenceProxyImpl> resumedThreads = context.myResumedThreads;
|
||||
if (resumedThreads != null) {
|
||||
for (ThreadReferenceProxyImpl thread : resumedThreads) {
|
||||
|
||||
Reference in New Issue
Block a user