From d447cb36ef9ce5ba18d62292a4a7d77329ca89e0 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 26 Jan 2005 12:43:41 +0300 Subject: [PATCH] fixed: 1. no stackframes for threads on first pause; 2. pause and then step - locks debugger --- .../debugger/actions/ForceStepIntoAction.java | 10 ++++- .../debugger/actions/ForceStepOverAction.java | 10 ++++- .../debugger/actions/StepIntoAction.java | 10 ++++- .../debugger/actions/StepOutAction.java | 10 ++++- .../debugger/actions/StepOverAction.java | 10 ++++- .../debugger/engine/DebugProcessEvents.java | 2 +- .../debugger/engine/DebugProcessImpl.java | 40 ++++++++++--------- .../engine/DebuggerManagerThreadImpl.java | 9 +++-- .../debugger/engine/SuspendManagerImpl.java | 2 + .../debugger/impl/DebuggerSession.java | 33 +++++++++++---- .../debugger/impl/InvokeAndWaitEventImpl.java | 22 +++++----- .../jdi/ThreadReferenceProxyImpl.java | 7 ++-- .../ui/impl/watch/ThreadDescriptorImpl.java | 3 +- 13 files changed, 113 insertions(+), 55 deletions(-) diff --git a/source/com/intellij/debugger/actions/ForceStepIntoAction.java b/source/com/intellij/debugger/actions/ForceStepIntoAction.java index c539d292bb7a..8b4c76feeec6 100644 --- a/source/com/intellij/debugger/actions/ForceStepIntoAction.java +++ b/source/com/intellij/debugger/actions/ForceStepIntoAction.java @@ -3,8 +3,10 @@ package com.intellij.debugger.actions; import com.intellij.debugger.DebuggerManager; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataConstants; @@ -27,7 +29,11 @@ public class ForceStepIntoAction extends AnAction { presentation.setEnabled(false); return; } - DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession(); - presentation.setEnabled(debuggerSession != null && debuggerSession.isPaused()); + final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext(); + DebuggerSession debuggerSession = context.getDebuggerSession(); + final boolean isPaused = debuggerSession != null && debuggerSession.isPaused(); + final SuspendContextImpl suspendContext = context.getSuspendContext(); + final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null; + presentation.setEnabled(isPaused && hasCurrentThread); } } diff --git a/source/com/intellij/debugger/actions/ForceStepOverAction.java b/source/com/intellij/debugger/actions/ForceStepOverAction.java index 9196dc251905..1407dcdfb124 100644 --- a/source/com/intellij/debugger/actions/ForceStepOverAction.java +++ b/source/com/intellij/debugger/actions/ForceStepOverAction.java @@ -7,7 +7,9 @@ import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.Project; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.engine.SuspendContextImpl; /* * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. @@ -30,8 +32,12 @@ public class ForceStepOverAction extends AnAction { presentation.setEnabled(false); return; } - DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession(); - presentation.setEnabled(debuggerSession != null && debuggerSession.isPaused()); + final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext(); + DebuggerSession debuggerSession = context.getDebuggerSession(); + final boolean isPaused = debuggerSession != null && debuggerSession.isPaused(); + final SuspendContextImpl suspendContext = context.getSuspendContext(); + final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null; + presentation.setEnabled(isPaused && hasCurrentThread); } } diff --git a/source/com/intellij/debugger/actions/StepIntoAction.java b/source/com/intellij/debugger/actions/StepIntoAction.java index a904b8ae3465..49e3e654eb5a 100644 --- a/source/com/intellij/debugger/actions/StepIntoAction.java +++ b/source/com/intellij/debugger/actions/StepIntoAction.java @@ -3,7 +3,9 @@ package com.intellij.debugger.actions; import com.intellij.debugger.DebuggerManager; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataConstants; @@ -26,7 +28,11 @@ public class StepIntoAction extends AnAction { presentation.setEnabled(false); return; } - DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession(); - presentation.setEnabled(debuggerSession != null && debuggerSession.isPaused()); + final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext(); + DebuggerSession debuggerSession = context.getDebuggerSession(); + final boolean isPaused = debuggerSession != null && debuggerSession.isPaused(); + final SuspendContextImpl suspendContext = context.getSuspendContext(); + final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null; + presentation.setEnabled(isPaused && hasCurrentThread); } } diff --git a/source/com/intellij/debugger/actions/StepOutAction.java b/source/com/intellij/debugger/actions/StepOutAction.java index d85b984b130a..13814741727f 100644 --- a/source/com/intellij/debugger/actions/StepOutAction.java +++ b/source/com/intellij/debugger/actions/StepOutAction.java @@ -3,8 +3,10 @@ package com.intellij.debugger.actions; import com.intellij.debugger.DebuggerManager; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataConstants; @@ -27,7 +29,11 @@ public class StepOutAction extends AnAction { presentation.setEnabled(false); return; } - DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession(); - presentation.setEnabled(debuggerSession != null && debuggerSession.isPaused()); + final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext(); + DebuggerSession debuggerSession = context.getDebuggerSession(); + final boolean isPaused = debuggerSession != null && debuggerSession.isPaused(); + final SuspendContextImpl suspendContext = context.getSuspendContext(); + final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null; + presentation.setEnabled(isPaused && hasCurrentThread); } } \ No newline at end of file diff --git a/source/com/intellij/debugger/actions/StepOverAction.java b/source/com/intellij/debugger/actions/StepOverAction.java index afb1be83ae4b..44bc0fbe8bb9 100644 --- a/source/com/intellij/debugger/actions/StepOverAction.java +++ b/source/com/intellij/debugger/actions/StepOverAction.java @@ -3,8 +3,10 @@ package com.intellij.debugger.actions; import com.intellij.debugger.DebuggerManager; import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataConstants; @@ -27,7 +29,11 @@ public class StepOverAction extends AnAction { presentation.setEnabled(false); return; } - DebuggerSession debuggerSession = (DebuggerManagerEx.getInstanceEx(project)).getContext().getDebuggerSession(); - presentation.setEnabled(debuggerSession != null && debuggerSession.isPaused()); + final DebuggerContextImpl context = (DebuggerManagerEx.getInstanceEx(project)).getContext(); + DebuggerSession debuggerSession = context.getDebuggerSession(); + final boolean isPaused = debuggerSession != null && debuggerSession.isPaused(); + final SuspendContextImpl suspendContext = context.getSuspendContext(); + final boolean hasCurrentThread = suspendContext != null && suspendContext.getThread() != null; + presentation.setEnabled(isPaused && hasCurrentThread); } } diff --git a/source/com/intellij/debugger/engine/DebugProcessEvents.java b/source/com/intellij/debugger/engine/DebugProcessEvents.java index 9d303f4a84e5..0efafc3f4cc2 100644 --- a/source/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/source/com/intellij/debugger/engine/DebugProcessEvents.java @@ -342,7 +342,7 @@ public class DebugProcessEvents extends DebugProcessImpl { if (LOG.isDebugEnabled()) { LOG.debug("STEPOUT doStep"); } - shouldResume = doStep(suspendContext, hint.getDepth(), hint); + shouldResume = doStep(suspendContext.getThread(), hint.getDepth(), hint); } if(!shouldResume && hint.isRestoreBreakpoints()) { diff --git a/source/com/intellij/debugger/engine/DebugProcessImpl.java b/source/com/intellij/debugger/engine/DebugProcessImpl.java index cc0f73c71b9c..62001b512d24 100644 --- a/source/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/source/com/intellij/debugger/engine/DebugProcessImpl.java @@ -212,18 +212,20 @@ public abstract class DebugProcessImpl implements DebugProcess { /** * - * @param suspendContext + * @return + * @param stepThread * @param depth * @param hint may be null - * @return */ - protected boolean doStep(SuspendContextImpl suspendContext, int depth, RequestHint hint) { - final ThreadReferenceProxyImpl currentThreadProxy = suspendContext.getThread(); - if (currentThreadProxy == null || !currentThreadProxy.isSuspended()) return false; + protected boolean doStep(ThreadReferenceProxyImpl stepThread, int depth, RequestHint hint) { + final ThreadReferenceProxyImpl currentThreadProxy = stepThread; + if (currentThreadProxy == null || !currentThreadProxy.isSuspended()) { + return false; + } if (LOG.isDebugEnabled()) { LOG.debug("DO_STEP: creating step request for " + currentThreadProxy.getThreadReference()); } - deleteStepRequests(suspendContext.getThread()); + deleteStepRequests(currentThreadProxy); EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager(); StepRequest stepRequest = requestManager.createStepRequest(currentThreadProxy.getThreadReference(), StepRequest.STEP_LINE, depth); DebuggerSettings settings = DebuggerSettings.getInstance(); @@ -264,7 +266,7 @@ public abstract class DebugProcessImpl implements DebugProcess { // [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occures continue; } - else if(threadReference.equals(requestsInThread.getThreadReference())) { + else /*if(threadReference.equals(requestsInThread.getThreadReference())) */{ toDelete.add(request); } } @@ -1153,9 +1155,9 @@ public abstract class DebugProcessImpl implements DebugProcess { public void contextAction() { showStatusText("Stepping out"); - if (doStep(getSuspendContext(), StepRequest.STEP_OUT, null)) { - super.contextAction(); - } + final SuspendContextImpl suspendContext = getSuspendContext(); + doStep(suspendContext.getThread(), StepRequest.STEP_OUT, null); + super.contextAction(); } } @@ -1169,11 +1171,11 @@ public abstract class DebugProcessImpl implements DebugProcess { public void contextAction() { showStatusText("Stepping into"); - RequestHint hint = new RequestHint(getSuspendContext(), StepRequest.STEP_INTO); + final SuspendContextImpl suspendContext = getSuspendContext(); + RequestHint hint = new RequestHint(suspendContext, StepRequest.STEP_INTO); hint.setIgnoreFilters(myIgnoreFilters); - if (doStep(getSuspendContext(), StepRequest.STEP_INTO, hint)) { - super.contextAction(); - } + doStep(suspendContext.getThread(), StepRequest.STEP_INTO, hint); + super.contextAction(); } } @@ -1187,15 +1189,17 @@ public abstract class DebugProcessImpl implements DebugProcess { public void contextAction() { showStatusText("Stepping over"); - RequestHint hint = new RequestHint(getSuspendContext(), StepRequest.STEP_OVER); + final SuspendContextImpl suspendContext = getSuspendContext(); + RequestHint hint = new RequestHint(suspendContext, StepRequest.STEP_OVER); hint.setRestoreBreakpoints(myIsIgnoreBreakpoints); - if (doStep(getSuspendContext(), StepRequest.STEP_OVER, hint)) { + final boolean succeeded = doStep(suspendContext.getThread(), StepRequest.STEP_OVER, hint); + if (succeeded) { if (myIsIgnoreBreakpoints) { DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().disableBreakpoints(DebugProcessImpl.this); } - super.contextAction(); } + super.contextAction(); } } @@ -1244,7 +1248,7 @@ public abstract class DebugProcessImpl implements DebugProcess { getVirtualMachineProxy().suspend(); logThreads(); SuspendContextImpl suspendContext = mySuspendManager.pushSuspendContext(EventRequest.SUSPEND_ALL, 0); - mySuspendManager.notifyPaused(suspendContext); + myDebugProcessDispatcher.getMulticaster().paused(suspendContext); } } diff --git a/source/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java b/source/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java index 94a4c1adb48f..0b27b0224941 100644 --- a/source/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java +++ b/source/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java @@ -11,6 +11,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.util.ProgressIndicatorListenerAdapter; import com.intellij.openapi.progress.util.ProgressWindowWithNotification; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.util.Alarm; import com.sun.jdi.VMDisconnectedException; @@ -47,17 +48,17 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread myEventContexts = new LinkedList(); + // contexts, paused at breakpoint or another debugger event requests. Note that thread, explicitly paused by user is not considered as + // "paused at breakpoint" and JDI prohibits data queries on its stackframes private final LinkedList myPausedContexts = new LinkedList(); private final Set myFrozenThreads = new HashSet(); diff --git a/source/com/intellij/debugger/impl/DebuggerSession.java b/source/com/intellij/debugger/impl/DebuggerSession.java index f485d8d29592..d721c85fdb59 100644 --- a/source/com/intellij/debugger/impl/DebuggerSession.java +++ b/source/com/intellij/debugger/impl/DebuggerSession.java @@ -27,6 +27,7 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiDocumentManager; import com.sun.jdi.request.EventRequest; +import com.sun.jdi.ThreadReference; import javax.swing.*; import java.util.ArrayList; @@ -170,9 +171,24 @@ public class DebuggerSession { } if(currentThread == null) { - currentThread = getProcess().getVirtualMachineProxy().allThreads().iterator().next(); + final Iterator iterator = getProcess().getVirtualMachineProxy().allThreads().iterator(); + while (iterator.hasNext()) { + currentThread = iterator.next(); + if (currentThread.status() == ThreadReference.THREAD_STATUS_RUNNING) { + break; + } + } } + while (!currentThread.isSuspended()) { + // wait until thread is considered suspended. Querying data from a thread immediately after VM.suspend() + // may result in IncompatibleThreadStateException, most likely some time after suspend() VM erroneously thinks that thread is still running + try { + Thread.sleep(10); + } + catch (InterruptedException e) { + } + } StackFrameProxyImpl proxy; try { @@ -370,18 +386,21 @@ public class DebuggerSession { } public void stepOut() { - mySteppingThroughThreads.add(getSuspendContext().getThread()); - resumeAction(myDebugProcess.createStepOutCommand(getSuspendContext()), EVENT_STEP); + final SuspendContextImpl suspendContext = getSuspendContext(); + mySteppingThroughThreads.add(suspendContext.getThread()); + resumeAction(myDebugProcess.createStepOutCommand(suspendContext), EVENT_STEP); } public void stepOver(boolean ignoreBreakpoints) { - mySteppingThroughThreads.add(getSuspendContext().getThread()); - resumeAction(myDebugProcess.createStepOverCommand(getSuspendContext(), ignoreBreakpoints), EVENT_STEP); + final SuspendContextImpl suspendContext = getSuspendContext(); + mySteppingThroughThreads.add(suspendContext.getThread()); + resumeAction(myDebugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints), EVENT_STEP); } public void stepInto(final boolean ignoreFilters) { - mySteppingThroughThreads.add(getSuspendContext().getThread()); - resumeAction(myDebugProcess.createStepIntoCommand(getSuspendContext(), ignoreFilters), EVENT_STEP); + final SuspendContextImpl suspendContext = getSuspendContext(); + mySteppingThroughThreads.add(suspendContext.getThread()); + resumeAction(myDebugProcess.createStepIntoCommand(suspendContext, ignoreFilters), EVENT_STEP); } public void runToCursor(Document document, int line) { diff --git a/source/com/intellij/debugger/impl/InvokeAndWaitEventImpl.java b/source/com/intellij/debugger/impl/InvokeAndWaitEventImpl.java index 830983e5d21a..0087366fb89b 100644 --- a/source/com/intellij/debugger/impl/InvokeAndWaitEventImpl.java +++ b/source/com/intellij/debugger/impl/InvokeAndWaitEventImpl.java @@ -9,21 +9,25 @@ import com.intellij.util.concurrency.Semaphore; * Time: 12:56:52 PM * To change this template use File | Settings | File Templates. */ -public abstract class InvokeAndWaitEventImpl implements InvokeAndWaitEvent{ - private Semaphore myInvokeAndWaitSemaphore; +public abstract class InvokeAndWaitEventImpl extends Semaphore implements InvokeAndWaitEvent{ public final void release() { - if(myInvokeAndWaitSemaphore != null) myInvokeAndWaitSemaphore.up(); + up(); } public final void hold() { - if(myInvokeAndWaitSemaphore == null) { - myInvokeAndWaitSemaphore = new Semaphore(); - } - myInvokeAndWaitSemaphore.down(); + down(); } - public void waitFor() { - myInvokeAndWaitSemaphore.waitFor(); + public final void down() { + super.down(); + } + + public final void up() { + super.up(); + } + + public final void waitFor() { + super.waitFor(); } } diff --git a/source/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java b/source/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java index 973714dda694..7107f1b1410f 100644 --- a/source/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java +++ b/source/com/intellij/debugger/jdi/ThreadReferenceProxyImpl.java @@ -23,10 +23,9 @@ public final class ThreadReferenceProxyImpl extends ObjectReferenceProxyImpl imp private String myName; private int myFrameCount = -1; // stackframes, 0 - bottom - private List myFramesFromBottom = new ArrayList(); - //cache build on the base of myFramesFromBottom - //0 - top - private List myFrames = new ArrayList(); + private List myFramesFromBottom = new ArrayList(); + //cache build on the base of myFramesFromBottom 0 - top, initially nothing is cached + private List myFrames = null; private ThreadGroupReferenceProxyImpl myThreadGroupProxy; diff --git a/source/com/intellij/debugger/ui/impl/watch/ThreadDescriptorImpl.java b/source/com/intellij/debugger/ui/impl/watch/ThreadDescriptorImpl.java index 6a40533a4a33..063c4809481f 100644 --- a/source/com/intellij/debugger/ui/impl/watch/ThreadDescriptorImpl.java +++ b/source/com/intellij/debugger/ui/impl/watch/ThreadDescriptorImpl.java @@ -90,9 +90,8 @@ public class ThreadDescriptorImpl extends NodeDescriptorImpl implements ThreadDe SuspendManager suspendManager = context.getDebugProcess().getSuspendManager(); myIsSuspended = suspendManager.isSuspended(thread); myIsExpandable = calcExpandable(suspendManager); - SuspendContextImpl threadContext = SuspendManagerUtil.findContextByThread(suspendManager, thread); mySuspendContext = SuspendManagerUtil.getSuspendContextForThread(context.getSuspendContext(), thread); - myIsAtBreakpoint = threadContext != null; + myIsAtBreakpoint = SuspendManagerUtil.findContextByThread(suspendManager, thread) != null; myIsCurrent = calcIsCurrent(context); myIsFrozen = suspendManager.isFrozen(getThreadReference()); }