IDEA-63378 Switching threads should be optional, not forced - correctly show stepping threads in running state

This commit is contained in:
Egor.Ushakov
2015-09-24 20:57:00 +03:00
parent 98b0fd4b7e
commit 190b8fa772
12 changed files with 76 additions and 42 deletions
@@ -416,6 +416,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
final int nextStepDepth = hint.getNextStepDepth(suspendContext);
if (nextStepDepth == RequestHint.RESUME) {
getSession().resetIgnoreStepFiltersFlag();
getSession().clearSteppingThrough();
shouldResume = true;
}
else if (nextStepDepth != RequestHint.STOP) {
@@ -40,6 +40,7 @@ import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
@@ -106,7 +107,7 @@ public class JavaDebugProcess extends XDebugProcess {
|| event == DebuggerSession.Event.REFRESH
&& myJavaSession.isPaused()) {
final SuspendContextImpl newSuspendContext = newContext.getSuspendContext();
if (newSuspendContext != null && newSuspendContext != getSession().getSuspendContext()) {
if (newSuspendContext != null && shouldApplyContext(newContext)) {
process.getManagerThread().schedule(new SuspendContextCommandImpl(newSuspendContext) {
@Override
public void contextAction() throws Exception {
@@ -119,10 +120,12 @@ public class JavaDebugProcess extends XDebugProcess {
XBreakpoint xBreakpoint = breakpoint.getXBreakpoint();
if (xBreakpoint != null) {
((XDebugSessionImpl)getSession()).breakpointReachedNoProcessing(xBreakpoint, newSuspendContext);
unsetPausedIfNeeded(newContext);
return;
}
}
getSession().positionReached(newSuspendContext);
unsetPausedIfNeeded(newContext);
}
});
}
@@ -181,6 +184,21 @@ public class JavaDebugProcess extends XDebugProcess {
});
}
private void unsetPausedIfNeeded(DebuggerContextImpl context) {
SuspendContextImpl suspendContext = context.getSuspendContext();
if (suspendContext != null && context.getThreadProxy() != suspendContext.getThread()) {
((XDebugSessionImpl)getSession()).unsetPaused();
}
}
private boolean shouldApplyContext(DebuggerContextImpl context) {
SuspendContextImpl suspendContext = context.getSuspendContext();
SuspendContextImpl currentContext = (SuspendContextImpl)getSession().getSuspendContext();
if (suspendContext != null && !suspendContext.equals(currentContext)) return true;
JavaExecutionStack currentExecutionStack = currentContext != null ? currentContext.getActiveExecutionStack() : null;
return currentExecutionStack == null || !Comparing.equal(context.getThreadProxy(), currentExecutionStack.getThreadProxy());
}
public void saveNodeHistory() {
saveNodeHistory(getDebuggerStateManager().getContext().getFrameProxy());
}
@@ -48,14 +48,11 @@ public class JavaExecutionStack extends XExecutionStack {
super(calcRepresentation(threadProxy), calcIcon(threadProxy, current));
myThreadProxy = threadProxy;
myDebugProcess = debugProcess;
if (current) {
initTopFrame();
}
}
private static Icon calcIcon(ThreadReferenceProxyImpl threadProxy, boolean current) {
if (current) {
return AllIcons.Debugger.ThreadCurrent;
return threadProxy.isSuspended() ? AllIcons.Debugger.ThreadCurrent : AllIcons.Debugger.ThreadRunning;
}
else if (threadProxy.isAtBreakpoint()) {
return AllIcons.Debugger.ThreadAtBreakpoint;
@@ -138,7 +138,7 @@ public class JavaStackFrame extends XStackFrame {
xFrame.computeChildren(node);
return;
}
myDebugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(myDebugProcess.getDebuggerContext()) {
myDebugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(myDebugProcess.getDebuggerContext(), myDescriptor.getFrameProxy().threadProxy()) {
@Override
public Priority getPriority() {
return Priority.NORMAL;
@@ -26,7 +26,6 @@ import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.containers.HashSet;
import com.intellij.xdebugger.frame.XExecutionStack;
import com.intellij.xdebugger.frame.XSuspendContext;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ThreadReference;
@@ -229,15 +228,18 @@ public abstract class SuspendContextImpl extends XSuspendContext implements Susp
@Nullable
@Override
public XExecutionStack getActiveExecutionStack() {
public JavaExecutionStack getActiveExecutionStack() {
return myActiveExecutionStack;
}
public void initExecutionStacks(ThreadReferenceProxyImpl newThread) {
public void initExecutionStacks(ThreadReferenceProxyImpl activeThread) {
DebuggerManagerThreadImpl.assertIsManagerThread();
myThread = newThread;
if (newThread != null) {
myActiveExecutionStack = new JavaExecutionStack(newThread, myDebugProcess, true);
if (myThread == null) {
myThread = activeThread;
}
if (activeThread != null) {
myActiveExecutionStack = new JavaExecutionStack(activeThread, myDebugProcess, myThread == activeThread);
myActiveExecutionStack.initTopFrame();
}
}
@@ -115,13 +115,6 @@ public class SuspendManagerImpl implements SuspendManager {
return suspendContext;
}
public SuspendContextImpl createDummyContext(@MagicConstant(flagsFromClass = EventRequest.class) int suspendPolicy) {
return new SuspendContextImpl(myDebugProcess, suspendPolicy, 0, null) {
@Override
protected void resumeImpl() {}
};
}
@Override
public SuspendContextImpl pushSuspendContext(final EventSet set) {
SuspendContextImpl suspendContext = new SuspendContextImpl(myDebugProcess, set.suspendPolicy(), set.size(), set) {
@@ -360,7 +353,7 @@ public class SuspendManagerImpl implements SuspendManager {
processVote(suspendContext);
}
LinkedList<SuspendContextImpl> getPausedContexts() {
public List<SuspendContextImpl> getPausedContexts() {
return myPausedContexts;
}
}
@@ -151,7 +151,6 @@ public final class DebuggerContextImpl implements DebuggerContext {
ThreadReferenceProxyImpl threadProxy,
StackFrameProxyImpl frameProxy) {
LOG.assertTrue(frameProxy == null || threadProxy == null || threadProxy == frameProxy.threadProxy());
LOG.assertTrue(session == null || session.getProcess() != null);
return new DebuggerContextImpl(session, session != null ? session.getProcess() : null, context, threadProxy, frameProxy, null, null, context == null);
}
@@ -111,7 +111,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
mySteppingThroughThread.set(threadProxy);
}
void clearSteppingThrough() {
public void clearSteppingThrough() {
mySteppingThroughThread.set(null);
}
@@ -469,6 +469,8 @@ public class DebuggerSession implements AbstractDebuggerSession {
LOG.debug("paused");
}
ThreadReferenceProxyImpl currentThread = suspendContext.getThread();
if (!shouldSetAsActiveContext(suspendContext)) {
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
@@ -476,7 +478,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
getContextManager().fireStateChanged(getContextManager().getContext(), Event.THREADS_REFRESH);
}
});
final ThreadReferenceProxyImpl thread = suspendContext.getThread();
ThreadReferenceProxyImpl thread = suspendContext.getThread();
if (thread != null) {
List<Pair<Breakpoint, com.sun.jdi.event.Event>> descriptors = DebuggerUtilsEx.getEventDescriptors(suspendContext);
if (!descriptors.isEmpty()) {
@@ -492,7 +494,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
@Override
public void contextAction() throws Exception {
final DebuggerContextImpl debuggerContext =
DebuggerContextImpl.createDebuggerContext(DebuggerSession.this, suspendContext, thread, null);
DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, suspendContext);
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
@@ -507,12 +509,17 @@ public class DebuggerSession implements AbstractDebuggerSession {
}).notify(getProject());
}
}
return;
if (((SuspendManagerImpl)myDebugProcess.getSuspendManager()).getPausedContexts().size() > 1) {
return;
}
else {
currentThread = mySteppingThroughThread.get();
}
}
else {
setSteppingThrough(currentThread);
}
setSteppingThrough(suspendContext.getThread());
ThreadReferenceProxyImpl currentThread = suspendContext.getThread();
final StackFrameContext positionContext;
if (currentThread == null) {
@@ -626,7 +633,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
getContextManager().setState(debuggerContext, State.PAUSED, Event.PAUSE, null);
getContextManager().setState(debuggerContext, State.PAUSED, Event.PAUSE, getDescription(debuggerContext));
}
});
}
@@ -650,25 +657,28 @@ public class DebuggerSession implements AbstractDebuggerSession {
@Override
public void resumed(SuspendContextImpl suspendContext) {
SuspendManager suspendManager = getProcess().getSuspendManager();
SuspendContextImpl context = suspendManager.getPausedContext();
SuspendContextImpl context = getProcess().getSuspendManager().getPausedContext();
ThreadReferenceProxyImpl steppingThread = null;
// single thread stepping
if (suspendContext != null
if (context != null
&& suspendContext != null
&& suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD
&& isSteppingThrough(suspendContext.getThread())) {
ThreadReferenceProxyImpl thread = suspendContext.getThread();
if (context == null || !Comparing.equal(context.getThread(), thread)) {
context = ((SuspendManagerImpl)suspendManager).createDummyContext(suspendContext.getSuspendPolicy());
context.setThread(thread.getThreadReference());
}
steppingThread = suspendContext.getThread();
}
final SuspendContextImpl currentContext = context;
final DebuggerContextImpl debuggerContext =
context != null ?
DebuggerContextImpl.createDebuggerContext(DebuggerSession.this,
context,
steppingThread != null ? steppingThread : context.getThread(),
null)
: null;
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
if (currentContext != null) {
getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, currentContext),
State.PAUSED, Event.CONTEXT, null);
if (debuggerContext != null) {
getContextManager().setState(debuggerContext, State.PAUSED, Event.CONTEXT, getDescription(debuggerContext));
}
else {
getContextManager().setState(SESSION_EMPTY_CONTEXT, State.RUNNING, Event.CONTEXT, null);
@@ -756,6 +766,14 @@ public class DebuggerSession implements AbstractDebuggerSession {
}
}
private static String getDescription(DebuggerContextImpl debuggerContext) {
SuspendContextImpl suspendContext = debuggerContext.getSuspendContext();
if (suspendContext != null && debuggerContext.getThreadProxy() != suspendContext.getThread()) {
return DebuggerBundle.message("status.paused.in.another.thread");
}
return null;
}
private class MyEvaluationListener implements EvaluationListener {
@Override
public void evaluationStarted(SuspendContextImpl context) {
@@ -176,7 +176,7 @@ class ReloadClassesWorker {
SuspendContextImpl suspendContext = context.getSuspendContext();
if (suspendContext != null) {
XExecutionStack stack = suspendContext.getActiveExecutionStack();
if (stack instanceof JavaExecutionStack) {
if (stack != null) {
((JavaExecutionStack)stack).initTopFrame();
}
}
@@ -193,6 +193,7 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy {
throw new EvaluateException(error.getMessage(), error);
}
@NotNull
@Override
public ThreadReferenceProxyImpl threadProxy() {
return myThreadProxy;
@@ -814,6 +814,10 @@ public class XDebugSessionImpl implements XDebugSession {
});
}
public void unsetPaused() {
myPaused.set(false);
}
@Override
public void positionReached(@NotNull final XSuspendContext suspendContext) {
enableBreakpoints();
@@ -91,6 +91,7 @@ status.step.into=Stepping into
status.step.over=Stepping over
status.run.to.cursor=Run to cursor
status.process.resumed=Process resumed
status.paused.in.another.thread=Paused in another thread
error.pop.bottom.stackframe=Cannot pop bottom frame
error.pop.stackframe=An error occurred while popping stack frame: {0}
error.class.not.loaded=Class not loaded : {0}