1. InterruptThread action available from the ThreadsPane (IDEA-23341)

2. ThreadsPane shows running threads and updates their state even if debug VM is not paused
3. tests fixed
This commit is contained in:
Eugene Zhuravlev
2010-09-08 08:27:25 +04:00
parent 4e94a38f4c
commit fb8ddd084b
22 changed files with 382 additions and 62 deletions
@@ -0,0 +1,98 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.debugger.actions;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import java.util.ArrayList;
import java.util.List;
/**
* User: lex
* Date: Sep 26, 2003
* Time: 7:35:09 PM
*/
public class InterruptThreadAction extends DebuggerAction{
public void actionPerformed(final AnActionEvent e) {
final DebuggerTreeNodeImpl[] nodes = getSelectedNodes(e.getDataContext());
if (nodes == null) {
return;
}
//noinspection ConstantConditions
final List<ThreadReferenceProxyImpl> threadsToInterrupt = new ArrayList<ThreadReferenceProxyImpl>();
for (final DebuggerTreeNodeImpl debuggerTreeNode : nodes) {
final NodeDescriptorImpl descriptor = debuggerTreeNode.getDescriptor();
if (descriptor instanceof ThreadDescriptorImpl) {
threadsToInterrupt.add(((ThreadDescriptorImpl)descriptor).getThreadReference());
}
}
if (!threadsToInterrupt.isEmpty()) {
final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
debuggerContext.getDebugProcess().getManagerThread().schedule(new DebuggerCommandImpl() {
protected void action() throws Exception {
for (ThreadReferenceProxyImpl thread : threadsToInterrupt) {
thread.getThreadReference().interrupt();
}
}
});
}
}
public void update(AnActionEvent e) {
final DebuggerTreeNodeImpl[] selectedNodes = getSelectedNodes(e.getDataContext());
boolean visible = false;
boolean enabled = false;
if(selectedNodes != null && selectedNodes.length > 0){
visible = true;
enabled = true;
for (DebuggerTreeNodeImpl selectedNode : selectedNodes) {
final NodeDescriptorImpl threadDescriptor = selectedNode.getDescriptor();
if (!(threadDescriptor instanceof ThreadDescriptorImpl)) {
visible = false;
break;
}
}
if (visible) {
for (DebuggerTreeNodeImpl selectedNode : selectedNodes) {
final ThreadDescriptorImpl threadDescriptor = (ThreadDescriptorImpl)selectedNode.getDescriptor();
if (threadDescriptor.isFrozen()) {
enabled = false;
break;
}
}
}
}
final Presentation presentation = e.getPresentation();
presentation.setText(DebuggerBundle.message("action.interrupt.thread.text"));
presentation.setVisible(visible);
presentation.setEnabled(enabled);
}
}
@@ -39,6 +39,9 @@ public class ContextUtil {
@Nullable
public static SourcePosition getSourcePosition(final StackFrameContext context) {
if (context == null) {
return null;
}
DebugProcessImpl debugProcess = (DebugProcessImpl)context.getDebugProcess();
if(debugProcess == null) {
return null;
@@ -18,6 +18,7 @@ package com.intellij.debugger.engine;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.execution.configurations.RunProfileState;
import com.sun.jdi.ThreadReference;
/**
* @author lex
@@ -66,6 +67,14 @@ public class DebugProcessAdapterImpl implements DebugProcessListener {
//To change body of implemented methods use File | Settings | File Templates.
}
//executed in manager thread
public void threadStarted(DebugProcess proc, ThreadReference thread) {
}
//executed in manager thread
public void threadStopped(DebugProcess proc, ThreadReference thread) {
}
public void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection) {
}
}
@@ -44,6 +44,9 @@ import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.event.*;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.ThreadDeathRequest;
import com.sun.jdi.request.ThreadStartRequest;
/**
* @author lex
@@ -132,20 +135,43 @@ public class DebugProcessEvents extends DebugProcessImpl {
while (!isStopped()) {
try {
final EventSet eventSet = eventQueue.remove();
if (myReturnValueWatcher != null && myReturnValueWatcher.isEnabled()) {
int processed = 0;
for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) {
final Event event = eventIterator.nextEvent();
final boolean methodWatcherActive = myReturnValueWatcher != null && myReturnValueWatcher.isEnabled();
int processed = 0;
for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) {
final Event event = eventIterator.nextEvent();
if (methodWatcherActive) {
if (event instanceof MethodExitEvent) {
if (myReturnValueWatcher.processMethodExitEvent((MethodExitEvent)event)) {
processed++;
}
continue;
}
}
if (processed == eventSet.size()) {
eventSet.resume();
continue;
if (event instanceof ThreadStartEvent) {
processed++;
final ThreadReference thread = ((ThreadStartEvent)event).thread();
getManagerThread().schedule(new DebuggerCommandImpl() {
protected void action() throws Exception {
myDebugProcessDispatcher.getMulticaster().threadStarted(DebugProcessEvents.this, thread);
}
});
}
else if (event instanceof ThreadDeathEvent) {
processed++;
final ThreadReference thread = ((ThreadDeathEvent)event).thread();
getManagerThread().schedule(new DebuggerCommandImpl() {
protected void action() throws Exception {
myDebugProcessDispatcher.getMulticaster().threadStopped(DebugProcessEvents.this, thread);
}
});
}
}
if (processed == eventSet.size()) {
eventSet.resume();
continue;
}
getManagerThread().invokeAndWait(new DebuggerCommandImpl() {
@@ -262,10 +288,19 @@ public class DebugProcessEvents extends DebugProcessImpl {
LOG.assertTrue(!isAttached());
if(myState.compareAndSet(STATE_INITIAL, STATE_ATTACHED)) {
final VirtualMachineProxyImpl machineProxy = getVirtualMachineProxy();
final EventRequestManager requestManager = machineProxy.eventRequestManager();
if (machineProxy.canGetMethodReturnValues()) {
myReturnValueWatcher = new MethodReturnValueWatcher(machineProxy.eventRequestManager());
myReturnValueWatcher = new MethodReturnValueWatcher(requestManager);
}
final ThreadStartRequest threadStartRequest = requestManager.createThreadStartRequest();
threadStartRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
threadStartRequest.enable();
final ThreadDeathRequest threadDeathRequest = requestManager.createThreadDeathRequest();
threadDeathRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
threadDeathRequest.enable();
DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().setInitialBreakpointsState();
myDebugProcessDispatcher.getMulticaster().processAttached(this);
@@ -113,6 +113,9 @@ public class SuspendManagerUtil {
}
public static SuspendContextImpl getSuspendContextForThread(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
if (suspendContext == null) {
return null;
}
SuspendContextImpl context = findContextByThread(suspendContext.getDebugProcess().getSuspendManager(), thread);
return context != null && !context.myInProgress ? context : suspendContext;
}
@@ -26,6 +26,7 @@ import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.engine.requests.RequestManagerImpl;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.debugger.ui.breakpoints.Breakpoint;
import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter;
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
@@ -565,6 +566,26 @@ public class DebuggerSession implements AbstractDebuggerSession {
});
mySteppingThroughThreads.clear();
}
public void threadStarted(DebugProcess proc, ThreadReference thread) {
((VirtualMachineProxyImpl)proc.getVirtualMachineProxy()).threadStarted(thread);
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
public void run() {
final DebuggerStateManager contextManager = getContextManager();
contextManager.fireStateChanged(contextManager.getContext(), EVENT_REFRESH_VIEWS_ONLY);
}
});
}
public void threadStopped(DebugProcess proc, ThreadReference thread) {
((VirtualMachineProxyImpl)proc.getVirtualMachineProxy()).threadStopped(thread);
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
public void run() {
final DebuggerStateManager contextManager = getContextManager();
contextManager.fireStateChanged(contextManager.getContext(), EVENT_REFRESH_VIEWS_ONLY);
}
});
}
}
private class MyEvaluationListener implements EvaluationListener {
@@ -143,6 +143,22 @@ public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy {
return myAllThreads.values();
}
public void threadStarted(ThreadReference thread) {
DebuggerManagerThreadImpl.assertIsManagerThread();
final Map<ThreadReference, ThreadReferenceProxyImpl> allThreads = myAllThreads;
if (allThreads != null && !allThreads.containsKey(thread)) {
allThreads.put(thread, new ThreadReferenceProxyImpl(this, thread));
}
}
public void threadStopped(ThreadReference thread) {
DebuggerManagerThreadImpl.assertIsManagerThread();
final Map<ThreadReference, ThreadReferenceProxyImpl> allThreads = myAllThreads;
if (allThreads != null) {
allThreads.remove(thread);
}
}
public void suspend() {
DebuggerManagerThreadImpl.assertIsManagerThread();
myPausePressedCount++;
@@ -564,7 +580,7 @@ public class VirtualMachineProxyImpl implements JdiTimer, VirtualMachineProxy {
if (!myNestedClassesCache.isEmpty()) {
myNestedClassesCache = new HashMap<ReferenceType, List<ReferenceType>>(myNestedClassesCache.size());
}
myAllThreadsDirty = true;
//myAllThreadsDirty = true;
myTimeStamp++;
}
@@ -46,7 +46,6 @@ import com.intellij.execution.ui.layout.LayoutViewOptions;
import com.intellij.execution.ui.layout.PlaceInGrid;
import com.intellij.ide.CommonActionsManager;
import com.intellij.ide.actions.ContextHelpAction;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
@@ -55,7 +54,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.content.AlertIcon;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManagerAdapter;
@@ -466,9 +464,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
}
}
public RunContentDescriptor attachToSession(final DebuggerSession session,
final ProgramRunner runner,
final ExecutionEnvironment env)
public RunContentDescriptor attachToSession(final DebuggerSession session, final ProgramRunner runner, final ExecutionEnvironment env)
throws ExecutionException {
disposeSession();
myDebuggerSession = session;
@@ -487,7 +483,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
myStateManager.fireStateChanged(newContext, event);
}
});
return initUI(getDebugProcess().getExecutionResult());
return initUI(session.getProcess().getExecutionResult());
}
private void attractFramesOnPause(final int event) {
@@ -29,6 +29,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.evaluation.TextWithImports;
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.jdi.LocalVariableProxyImpl;
@@ -104,7 +105,7 @@ public class FrameDebuggerTree extends DebuggerTree {
}
protected BuildNodeCommand getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
protected DebuggerCommandImpl getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
if (node.getDescriptor() instanceof StackFrameDescriptorImpl) {
return new BuildFrameTreeVariablesCommand(node);
}
@@ -17,14 +17,18 @@ package com.intellij.debugger.ui.impl;
import com.intellij.debugger.DebuggerInvocationUtil;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.debugger.settings.ThreadsViewSettings;
import com.intellij.debugger.ui.impl.watch.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.util.ui.tree.TreeModelAdapter;
@@ -66,28 +70,43 @@ public class ThreadsDebuggerTree extends DebuggerTree {
}
protected void build(DebuggerContextImpl context) {
buildWhenPaused(context, new RefreshThreadsTreelCommand(context));
DebuggerSession debuggerSession = context.getDebuggerSession();
final RefreshThreadsTreeCommand command = new RefreshThreadsTreeCommand(debuggerSession);
final int state = debuggerSession.getState();
if (ApplicationManager.getApplication().isUnitTestMode() || state == DebuggerSession.STATE_PAUSED || state == DebuggerSession.STATE_RUNNING) {
showMessage(MessageDescriptor.EVALUATING);
context.getDebugProcess().getManagerThread().schedule(command);
}
else {
showMessage(debuggerSession.getStateDescription());
}
}
private class RefreshThreadsTreelCommand extends RefreshDebuggerTreeCommand{
public RefreshThreadsTreelCommand(DebuggerContextImpl context) {
super(context);
private class RefreshThreadsTreeCommand extends DebuggerCommandImpl{
private final DebuggerSession mySession;
public RefreshThreadsTreeCommand(DebuggerSession session) {
mySession = session;
}
public void contextAction() throws Exception {
protected void action() throws Exception {
final DebuggerTreeNodeImpl root = getNodeFactory().getDefaultNode();
final DebugProcessImpl debugProcess = mySession.getProcess();
if(debugProcess == null || !debugProcess.isAttached()) {
return;
}
final DebuggerContextImpl context = mySession.getContextManager().getContext();
final SuspendContextImpl suspendContext = context.getSuspendContext();
final ThreadReferenceProxyImpl suspendContextThread = suspendContext != null? suspendContext.getThread() : null;
final boolean showGroups = ThreadsViewSettings.getInstance().SHOW_THREAD_GROUPS;
try {
DebugProcessImpl debugProcess = getDebuggerContext().getDebugProcess();
if(debugProcess == null || !debugProcess.isAttached()) {
return;
}
final ThreadReferenceProxyImpl currentThread = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD ? getSuspendContext().getThread() : null;
final ThreadReferenceProxyImpl currentThread = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD ? suspendContextThread : null;
final VirtualMachineProxyImpl vm = debugProcess.getVirtualMachineProxy();
final EvaluationContextImpl evaluationContext = getDebuggerContext().createEvaluationContext();
final EvaluationContextImpl evaluationContext = suspendContext != null? getDebuggerContext().createEvaluationContext() : null;
final NodeManagerImpl nodeManager = getNodeFactory();
if (showGroups) {
@@ -139,12 +158,11 @@ public class ThreadsDebuggerTree extends DebuggerTree {
}
}
final ThreadReferenceProxyImpl thread = getSuspendContext().getThread();
final boolean hasThreadToSelect = thread != null; // thread can be null if pause was pressed
final boolean hasThreadToSelect = suspendContextThread != null; // thread can be null if pause was pressed
final List<ThreadGroupReferenceProxyImpl> groups;
if (hasThreadToSelect && showGroups) {
groups = new ArrayList<ThreadGroupReferenceProxyImpl>();
for(ThreadGroupReferenceProxyImpl group = thread.threadGroupProxy(); group != null; group = group.parent()) {
for(ThreadGroupReferenceProxyImpl group = suspendContextThread.threadGroupProxy(); group != null; group = group.parent()) {
groups.add(group);
}
Collections.reverse(groups);
@@ -158,7 +176,7 @@ public class ThreadsDebuggerTree extends DebuggerTree {
getMutableModel().setRoot(root);
treeChanged();
if (hasThreadToSelect) {
selectThread(groups, thread, true);
selectThread(groups, suspendContextThread, true);
}
}
});
@@ -166,8 +184,6 @@ public class ThreadsDebuggerTree extends DebuggerTree {
private void selectThread(final List<ThreadGroupReferenceProxyImpl> pathToThread, final ThreadReferenceProxyImpl thread, final boolean expand) {
LOG.assertTrue(SwingUtilities.isEventDispatchThread());
class MyTreeModelAdapter extends TreeModelAdapter {
private void structureChanged(DebuggerTreeNodeImpl node) {
for(Enumeration enumeration = node.children(); enumeration.hasMoreElements(); ) {
@@ -17,20 +17,25 @@ package com.intellij.debugger.ui.impl;
import com.intellij.debugger.actions.DebuggerAction;
import com.intellij.debugger.actions.DebuggerActions;
import com.intellij.debugger.impl.DebuggerContextUtil;
import com.intellij.debugger.impl.DebuggerStateManager;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.debugger.impl.*;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.ui.impl.watch.DebuggerTree;
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPopupMenu;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.NonNls;
import java.awt.*;
@@ -39,8 +44,10 @@ import java.awt.event.KeyEvent;
public class ThreadsPanel extends DebuggerTreePanel{
@NonNls private static final String HELP_ID = "debugging.debugThreads";
private final Alarm myUpdateLabelsAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
private static final int LABELS_UPDATE_DELAY_MS = 200;
public ThreadsPanel(Project project, DebuggerStateManager stateManager) {
public ThreadsPanel(Project project, final DebuggerStateManager stateManager) {
super(project, stateManager);
final Disposable disposable = DebuggerAction.installEditAction(getThreadsTree(), DebuggerActions.EDIT_FRAME_SOURCE);
@@ -60,8 +67,88 @@ public class ThreadsPanel extends DebuggerTreePanel{
}
});
add(ScrollPaneFactory.createScrollPane(getThreadsTree()), BorderLayout.CENTER);
stateManager.addListener(new DebuggerContextListener() {
public void changeEvent(DebuggerContextImpl newContext, int event) {
if (DebuggerSession.EVENT_ATTACHED == event || DebuggerSession.EVENT_RESUME == event) {
startLabelsUpdate();
}
else if (DebuggerSession.EVENT_PAUSE == event || DebuggerSession.EVENT_DETACHED == event || DebuggerSession.EVENT_DISPOSE == event) {
myUpdateLabelsAlarm.cancelAllRequests();
}
if (DebuggerSession.EVENT_DETACHED == event || DebuggerSession.EVENT_DISPOSE == event) {
stateManager.removeListener(this);
}
}
});
startLabelsUpdate();
}
private void startLabelsUpdate() {
myUpdateLabelsAlarm.cancelAllRequests();
myUpdateLabelsAlarm.addRequest(new Runnable() {
public void run() {
boolean updateScheduled = false;
try {
if (isUpdateEnabled()) {
final ThreadsDebuggerTree tree = getThreadsTree();
final DebuggerTreeNodeImpl root = (DebuggerTreeNodeImpl)tree.getModel().getRoot();
if (root != null) {
final DebugProcessImpl process = getContext().getDebugProcess();
if (process != null) {
process.getManagerThread().invoke(new DebuggerCommandImpl() {
protected void action() throws Exception {
try {
updateNodeLabels(root);
}
finally {
reschedule();
}
}
protected void commandCancelled() {
reschedule();
}
});
updateScheduled = true;
}
}
}
}
finally {
if (!updateScheduled) {
reschedule();
}
}
}
private void reschedule() {
final DebuggerSession session = getContext().getDebuggerSession();
if (session.isAttached() && !session.isPaused()) {
myUpdateLabelsAlarm.addRequest(this, LABELS_UPDATE_DELAY_MS, ModalityState.NON_MODAL);
}
}
}, LABELS_UPDATE_DELAY_MS, ModalityState.NON_MODAL);
}
@Override
public void dispose() {
Disposer.dispose(myUpdateLabelsAlarm);
super.dispose();
}
private static void updateNodeLabels(DebuggerTreeNodeImpl from) {
final int childCount = from.getChildCount();
for (int idx = 0; idx < childCount; idx++) {
final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)from.getChildAt(idx);
child.getDescriptor().updateRepresentation(null, new DescriptorLabelListener() {
public void labelChanged() {
child.labelChanged();
}
});
updateNodeLabels(child);
}
}
protected DebuggerTree createTreeView() {
return new ThreadsDebuggerTree(getProject());
}
@@ -23,9 +23,9 @@ import com.intellij.debugger.ui.DebuggerView;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.actionSystem.ShortcutSet;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.Alarm;
import com.sun.jdi.VMDisconnectedException;
@@ -37,7 +37,7 @@ public abstract class UpdatableDebuggerView extends JPanel implements DebuggerVi
private final Project myProject;
private final DebuggerStateManager myStateManager;
protected final Alarm myRebuildAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
private volatile boolean myRefreshNeeded = true;
protected volatile boolean myRefreshNeeded = true;
protected final java.util.List<Disposable> myDisposables = new ArrayList<Disposable>();
private boolean myUpdateEnabled;
@@ -118,9 +118,9 @@ public abstract class UpdatableDebuggerView extends JPanel implements DebuggerVi
}
public void dispose() {
myRebuildAlarm.dispose();
Disposer.dispose(myRebuildAlarm);
for (Disposable disposable : myDisposables) {
disposable.dispose();
Disposer.dispose(disposable);
}
myDisposables.clear();
}
@@ -23,8 +23,10 @@ package com.intellij.debugger.ui.impl.watch;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.DebuggerInvocationUtil;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
@@ -198,16 +200,16 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
}
final DebugProcessImpl debugProcess = getDebuggerContext().getDebugProcess();
if (debugProcess != null) {
BuildNodeCommand command = getBuildNodeCommand(node);
DebuggerCommandImpl command = getBuildNodeCommand(node);
if (command != null) {
command.getNode().add(myNodeManager.createMessageNode(MessageDescriptor.EVALUATING));
node.add(myNodeManager.createMessageNode(MessageDescriptor.EVALUATING));
debugProcess.getManagerThread().schedule(command);
}
}
}
// todo: convert "if" into instance method call
protected BuildNodeCommand getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
protected DebuggerCommandImpl getBuildNodeCommand(final DebuggerTreeNodeImpl node) {
if (node.getDescriptor() instanceof StackFrameDescriptorImpl) {
return new BuildStackFrameCommand(node);
}
@@ -668,19 +670,24 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
}
}
private class BuildThreadGroupCommand extends BuildNodeCommand {
private class BuildThreadGroupCommand extends DebuggerCommandImpl {
private final DebuggerTreeNodeImpl myNode;
protected final List<DebuggerTreeNode> myChildren = new LinkedList<DebuggerTreeNode>();
public BuildThreadGroupCommand(DebuggerTreeNodeImpl node) {
super(node);
myNode = node;
}
public void threadAction() {
ThreadGroupDescriptorImpl groupDescriptor = (ThreadGroupDescriptorImpl)getNode().getDescriptor();
protected void action() throws Exception {
ThreadGroupDescriptorImpl groupDescriptor = (ThreadGroupDescriptorImpl)myNode.getDescriptor();
ThreadGroupReferenceProxyImpl threadGroup = groupDescriptor.getThreadGroupReference();
List<ThreadReferenceProxyImpl> threads = new ArrayList<ThreadReferenceProxyImpl>(threadGroup.threads());
Collections.sort(threads, ThreadReferenceProxyImpl.ourComparator);
EvaluationContextImpl evaluationContext = getDebuggerContext().createEvaluationContext();
final DebuggerContextImpl debuggerContext = getDebuggerContext();
final SuspendContextImpl suspendContext = debuggerContext.getSuspendContext();
final EvaluationContextImpl evaluationContext = suspendContext != null? debuggerContext.createEvaluationContext() : null;
boolean showCurrent = ThreadsViewSettings.getInstance().SHOW_CURRENT_THREAD;
@@ -702,8 +709,7 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
for (ThreadReferenceProxyImpl thread : threads) {
if (thread != null) {
DebuggerTreeNodeImpl threadNode =
myNodeManager.createNode(myNodeManager.getThreadDescriptor(groupDescriptor, thread), evaluationContext);
final DebuggerTreeNodeImpl threadNode = myNodeManager.createNode(myNodeManager.getThreadDescriptor(groupDescriptor, thread), evaluationContext);
if (showCurrent && ((ThreadDescriptorImpl)threadNode.getDescriptor()).isCurrent()) {
threadNodes.add(0, threadNode);
}
@@ -717,6 +723,18 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi
updateUI(true);
}
protected void updateUI(final boolean scrollToVisible) {
DebuggerInvocationUtil.swingInvokeLater(getProject(), new Runnable() {
public void run() {
myNode.removeAllChildren();
for (DebuggerTreeNode debuggerTreeNode : myChildren) {
myNode.add(debuggerTreeNode);
}
myNode.childrenChanged(scrollToVisible);
}
});
}
}
public void hideTooltip() {
@@ -37,7 +37,7 @@ public class ThisDescriptorImpl extends ValueDescriptorImpl{
}
public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
return evaluationContext.getThisObject();
return evaluationContext != null? evaluationContext.getThisObject() : null;
}
public String getName() {
@@ -70,7 +70,6 @@ public class ThreadDescriptorImpl extends NodeDescriptorImpl implements ThreadDe
if (grname != null && !"SYSTEM".equalsIgnoreCase(grname)) {
return DebuggerBundle.message("label.thread.node.in.group", myName, thread.uniqueID(), threadStatusText, grname);
}
return DebuggerBundle.message("label.thread.node", myName, thread.uniqueID(), threadStatusText);
}
catch (ObjectCollectedException e) {
@@ -96,20 +95,20 @@ public class ThreadDescriptorImpl extends NodeDescriptorImpl implements ThreadDe
public void setContext(EvaluationContextImpl context) {
final ThreadReferenceProxyImpl thread = getThreadReference();
final SuspendManager suspendManager = context.getDebugProcess().getSuspendManager();
final SuspendContextImpl suspendContext = context.getSuspendContext();
final SuspendManager suspendManager = context != null? context.getDebugProcess().getSuspendManager() : null;
final SuspendContextImpl suspendContext = context != null? context.getSuspendContext() : null;
try {
myIsSuspended = suspendManager.isSuspended(thread);
myIsSuspended = suspendManager != null? suspendManager.isSuspended(thread) : thread.isSuspended();
}
catch (ObjectCollectedException e) {
myIsSuspended = false;
}
myIsExpandable = calcExpandable(myIsSuspended);
mySuspendContext = SuspendManagerUtil.getSuspendContextForThread(suspendContext, thread);
myIsAtBreakpoint = SuspendManagerUtil.findContextByThread(suspendManager, thread) != null;
myIsCurrent = suspendContext.getThread() == thread;
myIsFrozen = suspendManager.isFrozen(thread);
myIsAtBreakpoint = suspendManager != null? SuspendManagerUtil.findContextByThread(suspendManager, thread) != null : thread.getThreadReference().isAtBreakpoint();
myIsCurrent = suspendContext != null? suspendContext.getThread() == thread : false;
myIsFrozen = suspendManager != null? suspendManager.isFrozen(thread) : myIsSuspended;
}
private boolean calcExpandable(final boolean isSuspended) {
@@ -15,6 +15,7 @@
*/
package com.intellij.debugger.ui.impl.watch;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
@@ -22,7 +23,6 @@ import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.ui.tree.ThreadGroupDescriptor;
import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
import com.intellij.debugger.DebuggerBundle;
import com.sun.jdi.ObjectCollectedException;
public class ThreadGroupDescriptorImpl extends NodeDescriptorImpl implements ThreadGroupDescriptor{
@@ -64,7 +64,7 @@ public class ThreadGroupDescriptorImpl extends NodeDescriptorImpl implements Thr
}
public void setContext(EvaluationContextImpl context) {
ThreadReferenceProxyImpl threadProxy = context.getSuspendContext().getThread();
ThreadReferenceProxyImpl threadProxy = context != null? context.getSuspendContext().getThread() : null;
myIsCurrent = threadProxy != null && isDescendantGroup(threadProxy.threadGroupProxy());
myIsExpandable = calcExpandable();
}
@@ -170,7 +170,7 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements
@Nullable
private static ObjectReference getTargetExceptionWithStackTraceFilled(final EvaluationContextImpl evaluationContext, EvaluateException ex){
final ObjectReference exceptionObj = ex.getExceptionFromTargetVM();
if (exceptionObj != null) {
if (exceptionObj != null && evaluationContext != null) {
try {
final ReferenceType refType = exceptionObj.referenceType();
final List<Method> methods = refType.methodsByName("getStackTrace", "()[Ljava/lang/StackTraceElement;");
@@ -18,6 +18,7 @@ package com.intellij.debugger.engine;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.execution.configurations.RunProfileState;
import com.sun.jdi.ThreadReference;
public class DebugProcessAdapter implements DebugProcessListener{
//executed in manager thread
@@ -44,6 +45,14 @@ public class DebugProcessAdapter implements DebugProcessListener{
}
//executed in manager thread
public void threadStarted(DebugProcess proc, ThreadReference thread) {
}
//executed in manager thread
public void threadStopped(DebugProcess proc, ThreadReference thread) {
}
public void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection) {
}
@@ -18,6 +18,7 @@ package com.intellij.debugger.engine;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.execution.configurations.RunProfileState;
import com.sun.jdi.ThreadReference;
import java.util.EventListener;
@@ -39,5 +40,9 @@ public interface DebugProcessListener extends EventListener{
void processAttached(DebugProcess process);
void attachException(RunProfileState state, ExecutionException exception, RemoteConnection remoteConnection);
void threadStarted(DebugProcess proc, ThreadReference thread);
void threadStopped(DebugProcess proc, ThreadReference thread);
}
@@ -829,6 +829,7 @@ action.Debugger.SetValue.text=Set Value...
action.Debugger.ShowFrame.text=Show Frame
action.Debugger.ResumeThread.text=Resume
action.Debugger.FreezeThread.text=Freeze
action.Debugger.InterruptThread.text=Interrupt
action.Debugger.MuteBreakpoints.text=Mute Breakpoints
action.Debugger.MuteBreakpoints.description=Mute/unmute all breakpoints in a debug session.
action.Debugger.MarkObject.text=Mark Object...
@@ -31,6 +31,7 @@ action.remove.watch.text={0,choice, 1#Remove Watch|2#Remove Watches}
progress.evaluating=Evaluating {0}
action.resume.thread.text.resume=Resume
action.resume.thread.text.unfreeze=Unfreeze
action.interrupt.thread.text=Interrupt
title.set.value=Set Value
warning.recalculate=The value will be recalculated
progress.set.value=Setting value...
+2
View File
@@ -308,6 +308,7 @@
<action id="Debugger.ShowFrame" class="com.intellij.debugger.actions.ShowFrameAction"/>
<action id="Debugger.ResumeThread" class="com.intellij.debugger.actions.ResumeThreadAction"/>
<action id="Debugger.FreezeThread" class="com.intellij.debugger.actions.FreezeThreadAction"/>
<action id="Debugger.InterruptThread" class="com.intellij.debugger.actions.InterruptThreadAction"/>
<action id="Debugger.FocusOnBreakpoint" class="com.intellij.debugger.ui.breakpoints.actions.FocusOnBreakpointAction"/>
</group>
@@ -591,6 +592,7 @@
<group id="Debugger.ThreadsPanelPopup">
<!--<reference ref="Debugger.ResumeThread"/>-->
<!--<reference ref="Debugger.FreezeThread"/>-->
<reference ref="Debugger.InterruptThread"/>
<!--<reference ref="Debugger.ShowFrame"/>-->
<reference ref="Debugger.PopFrame"/>
<!--<reference ref="Debugger.EditFrameSource"/>-->