From ee9c51a046c41490b023b9d32d0a5f3ca77f7c4c Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Mon, 16 Jun 2008 18:30:54 +0000 Subject: [PATCH] [236765] - [pda] Add multi-threading capability to PDA --- .../launch/AbstractContainerVMNode.java | 110 +- .../launch/AbstractLaunchVMProvider.java | 206 ++++ .../launch/AbstractThreadVMNode.java | 71 +- .../pda/ui/actions/PDATerminateCommand.java | 4 +- .../viewmodel/launch/PDALaunchVMProvider.java | 97 +- .../ui/viewmodel/launch/PDAProgramVMNode.java | 354 ------ .../ui/viewmodel/launch/PDAThreadsVMNode.java | 156 +++ .../launch/PDAVirtualMachineVMNode.java | 208 ++++ .../pdavm/docs/protocol.html | 170 ++- .../dd/examples/pdavm/PDAVirtualMachine.java | 1037 +++++++++++------ .../pdavm/tests/vmtest3.pda | 2 + .../pdavm/tests/vmtest9.pda | 23 + .../pda/launch/PDAServicesInitSequence.java | 4 +- .../examples/pda/service/PDABreakpoints.java | 22 +- .../pda/service/PDACommandControl.java | 16 +- .../examples/pda/service/PDAExpressions.java | 20 +- .../dd/examples/pda/service/PDARegisters.java | 4 +- .../examples/pda/service/PDARunControl.java | 560 +++++++-- .../dd/examples/pda/service/PDAStack.java | 66 +- .../examples/pda/service/PDAStartedEvent.java | 8 +- .../pda/service/PDATerminatedEvent.java | 8 +- .../pda/service/PDAThreadDMContext.java | 48 + ...t.java => PDAVirtualMachineDMContext.java} | 18 +- .../service/commands/AbstractPDACommand.java | 4 +- .../commands/PDAClearBreakpointCommand.java | 4 +- .../pda/service/commands/PDADataCommand.java | 11 +- .../service/commands/PDADropFrameCommand.java | 23 +- .../pda/service/commands/PDAEvalCommand.java | 17 +- .../service/commands/PDAEventStopCommand.java | 4 +- .../pda/service/commands/PDAExitCommand.java | 4 +- .../service/commands/PDAPopDataCommand.java | 11 +- .../service/commands/PDAPushDataCommand.java | 11 +- .../service/commands/PDAResumeCommand.java | 18 +- .../commands/PDASetBreakpointCommand.java | 25 +- .../service/commands/PDASetDataCommand.java | 11 +- .../service/commands/PDASetVarCommand.java | 11 +- .../pda/service/commands/PDAStackCommand.java | 11 +- .../pda/service/commands/PDAStepCommand.java | 22 +- .../commands/PDAStepReturnCommand.java | 22 +- .../service/commands/PDASuspendCommand.java | 18 +- .../service/commands/PDAVMResumeCommand.java | 39 + .../service/commands/PDAVMSuspendCommand.java | 39 + .../pda/service/commands/PDAVarCommand.java | 12 +- .../pda/service/commands/PDAWatchCommand.java | 10 +- .../tests/pda/service/command/BasicTests.java | 2 +- .../command/CommandControlTestsBase.java | 2 +- .../pda/service/command/PDATestCommand.java | 4 +- .../dd/tests/pda/service/command/Test1.java | 2 +- .../dd/tests/pda/service/command/Test2.java | 208 +++- .../dd/tests/pda/service/command/Test3.java | 48 +- .../dd/tests/pda/service/command/Test6.java | 67 +- .../dd/tests/pda/service/command/Test8.java | 92 +- .../dd/tests/pda/service/command/Test9.java | 192 +++ .../ui/viewmodel/launch/ContainerVMNode.java | 60 +- .../ui/viewmodel/launch/LaunchVMProvider.java | 164 +-- 55 files changed, 2905 insertions(+), 1475 deletions(-) create mode 100644 plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractLaunchVMProvider.java delete mode 100644 plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAProgramVMNode.java create mode 100644 plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAThreadsVMNode.java create mode 100644 plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java create mode 100644 plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest9.pda create mode 100644 plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAThreadDMContext.java rename plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/{PDAProgramDMContext.java => PDAVirtualMachineDMContext.java} (82%) create mode 100644 plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMResumeCommand.java create mode 100644 plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMSuspendCommand.java create mode 100644 plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test9.java diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java index 1ba4920289c..99ec56d2a9c 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java @@ -12,19 +12,21 @@ package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch; import java.util.concurrent.RejectedExecutionException; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DsfRunnable; import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMEvent; import org.eclipse.dd.dsf.debug.service.IRunControl; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerResumedDMEvent; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent; -import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExitedDMEvent; import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent; import org.eclipse.dd.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent; import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.IVMContext; import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; @@ -40,14 +42,16 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; public abstract class AbstractContainerVMNode extends AbstractDMVMNode implements IElementLabelProvider { public AbstractContainerVMNode(AbstractDMVMProvider provider, DsfSession session) { - super(provider, session, IRunControl.IExecutionDMContext.class); + super(provider, session, IRunControl.IContainerDMContext.class); } public void update(final ILabelUpdate[] updates) { try { getSession().getExecutor().execute(new DsfRunnable() { public void run() { - updateLabelInSessionThread(updates); + for (final ILabelUpdate update : updates) { + updateLabelInSessionThread(update); + } }}); } catch (RejectedExecutionException e) { for (ILabelUpdate update : updates) { @@ -62,26 +66,36 @@ public abstract class AbstractContainerVMNode extends AbstractDMVMNode implement * @param updates the pending label updates * @see {@link #update(ILabelUpdate[]) */ - protected abstract void updateLabelInSessionThread(ILabelUpdate[] updates); + protected abstract void updateLabelInSessionThread(ILabelUpdate update); + @Override + public void getContextsForEvent(VMDelta parentDelta, Object e, final DataRequestMonitor rm) { + super.getContextsForEvent(parentDelta, e, rm); + } + public int getDeltaFlags(Object e) { - if (e instanceof IContainerResumedDMEvent && - ((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) - { - return IModelDelta.CONTENT; + IDMContext dmc = e instanceof IDMEvent ? ((IDMEvent)e).getDMContext() : null; + + if (e instanceof IContainerResumedDMEvent) { + if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) + { + return IModelDelta.CONTENT; + } } else if (e instanceof IContainerSuspendedDMEvent) { - // no change, update happens on FullStackRefreshEvent return IModelDelta.NO_CHANGE; } else if (e instanceof FullStackRefreshEvent) { - return IModelDelta.CONTENT; - } else if (e instanceof ISteppingTimedOutEvent && - ((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) - { - return IModelDelta.CONTENT; + if (dmc instanceof IContainerDMContext) { + return IModelDelta.CONTENT; + } + } else if (e instanceof ISteppingTimedOutEvent) { + if (dmc instanceof IContainerDMContext) + { + return IModelDelta.CONTENT; + } } else if (e instanceof IExitedDMEvent) { return IModelDelta.CONTENT; } else if (e instanceof IStartedDMEvent) { - if (((IStartedDMEvent) e).getDMContext() instanceof IContainerDMContext) { + if (dmc instanceof IContainerDMContext) { return IModelDelta.EXPAND | IModelDelta.SELECT; } else { return IModelDelta.CONTENT; @@ -91,37 +105,63 @@ public abstract class AbstractContainerVMNode extends AbstractDMVMNode implement } public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) { - if(e instanceof IContainerResumedDMEvent && - ((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) - { - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + IDMContext dmc = e instanceof IDMEvent ? ((IDMEvent)e).getDMContext() : null; + + if(e instanceof IContainerResumedDMEvent) { + // Container resumed: + // - If not stepping, update the container and the execution + // contexts under it. + // - If stepping, do nothing to avoid too many updates. If a + // time-out is reached before the step completes, the + // ISteppingTimedOutEvent will trigger a full refresh. + if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) + { + parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + } } else if (e instanceof IContainerSuspendedDMEvent) { - // do nothing + // Container suspended. Do nothing here to give the stack the + // priority in updating. The container and threads will update as + // a result of FullStackRefreshEvent. } else if (e instanceof FullStackRefreshEvent) { - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); - } else if (e instanceof ISteppingTimedOutEvent && - ((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) - { - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); - // Workaround for bug 233730: we need to add a separate delta node for the state flag in - // order to trigger an update of the run control actions. - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.STATE); + // Full-stack refresh event is generated following a suspended event + // and a fixed delay. If the suspended event was generated for the + // container refresh the whole container. + if (dmc instanceof IContainerDMContext) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + } + } else if (e instanceof ISteppingTimedOutEvent) { + // Stepping time-out indicates that a step operation is taking + // a long time, and the view needs to be refreshed to show + // the user that the program is running. + // If the step was issued for the whole container refresh + // the whole container. + if (dmc instanceof IContainerDMContext) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + } } else if (e instanceof IExitedDMEvent) { - IExecutionDMContext exeContext= ((IExitedDMEvent) e).getDMContext(); - if (exeContext instanceof IContainerDMContext) { + // An exited event could either be for a thread within a container + // or for the container itself. + // If a container exited, refresh the parent element so that the + // container may be removed. + // If a thread exited within a container, refresh that container. + if (dmc instanceof IContainerDMContext) { parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); } else { - IContainerDMContext containerCtx = DMContexts.getAncestorOfType(exeContext, IContainerDMContext.class); + IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class); if (containerCtx != null) { parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT); } } } else if (e instanceof IStartedDMEvent) { - IExecutionDMContext exeContext= ((IStartedDMEvent) e).getDMContext(); - if (exeContext instanceof IContainerDMContext) { - parentDelta.addNode(createVMContext(exeContext), IModelDelta.EXPAND | IModelDelta.SELECT); + // A started event could either be for a thread within a container + // or for the container itself. + // If a container started, issue an expand and select event to + // show the threads in the new container. + // Note: the EXPAND flag implies refreshing the parent element. + if (dmc instanceof IContainerDMContext) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.EXPAND | IModelDelta.SELECT); } else { - IContainerDMContext containerCtx = DMContexts.getAncestorOfType(exeContext, IContainerDMContext.class); + IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class); if (containerCtx != null) { parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT); } diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractLaunchVMProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractLaunchVMProvider.java new file mode 100644 index 00000000000..da4bdbe3d13 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractLaunchVMProvider.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + * Ericsson - Modified for new functionality + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.datamodel.IDMEvent; +import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; +import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; +import org.eclipse.dd.dsf.ui.viewmodel.IVMModelProxy; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchesListener2; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; + + +/** + * + */ +@SuppressWarnings("restriction") +public class AbstractLaunchVMProvider extends AbstractDMVMProvider + implements IDebugEventSetListener, ILaunchesListener2 +{ + /** + * Delay (in milliseconds) before a full stack trace will be requested. + */ + private static final int FRAME_UPDATE_DELAY= 200; + + private final Map> fRefreshStackFramesFutures = new HashMap>(); + + @ThreadSafe + public AbstractLaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) + { + super(adapter, presentationContext, session); + } + + @Override + protected IVMUpdatePolicy[] createUpdateModes() { + return new IVMUpdatePolicy[] { new DelayedStackRefreshUpdatePolicy() }; + } + + public void handleDebugEvents(final DebugEvent[] events) { + if (isDisposed()) return; + + // We're in session's executor thread. Re-dispach to VM Adapter + // executor thread and then call root layout node. + try { + getExecutor().execute(new Runnable() { + public void run() { + if (isDisposed()) return; + + for (final DebugEvent event : events) { + handleEvent(event); + } + }}); + } catch (RejectedExecutionException e) { + // Ignore. This exception could be thrown if the provider is being + // shut down. + } + } + + @Override + protected void handleEvent(IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) { + super.handleEvent(proxyStrategy, event, rm); + + if (event instanceof IRunControl.ISuspendedDMEvent) { + final IExecutionDMContext exeContext= ((IRunControl.ISuspendedDMEvent) event).getDMContext(); + ScheduledFuture refreshStackFramesFuture = getRefreshFuture(exeContext); + // trigger delayed full stack frame update + if (refreshStackFramesFuture != null) { + // cancel previously scheduled frame update + refreshStackFramesFuture.cancel(false); + } + + refreshStackFramesFuture = getSession().getExecutor().schedule( + new DsfRunnable() { + public void run() { + if (getSession().isActive()) { + getExecutor().execute(new Runnable() { + public void run() { + // trigger full stack frame update + ScheduledFuture future= fRefreshStackFramesFutures.get(exeContext); + if (future != null && !isDisposed()) { + fRefreshStackFramesFutures.remove(exeContext); + handleEvent(new FullStackRefreshEvent(exeContext)); + } + }}); + } + } + }, + FRAME_UPDATE_DELAY, TimeUnit.MILLISECONDS); + fRefreshStackFramesFutures.put(exeContext, refreshStackFramesFuture); + } else if (event instanceof IRunControl.IResumedDMEvent) { + IExecutionDMContext exeContext= ((IRunControl.IResumedDMEvent) event).getDMContext(); + ScheduledFuture refreshStackFramesFuture= fRefreshStackFramesFutures.get(exeContext); + if (refreshStackFramesFuture != null) { + // cancel previously scheduled frame update + refreshStackFramesFuture.cancel(false); + fRefreshStackFramesFutures.remove(exeContext); + } + } + } + + /** + * Returns the future for the given execution context or for any child of the + * given execution context. + */ + private ScheduledFuture getRefreshFuture(IExecutionDMContext execCtx) { + for (IExecutionDMContext refreshCtx : fRefreshStackFramesFutures.keySet()) { + if (refreshCtx.equals(execCtx) || DMContexts.isAncestorOf(refreshCtx, execCtx)) { + return fRefreshStackFramesFutures.remove(refreshCtx); + } + } + return null; + } + + @Override + public void dispose() { + DebugPlugin.getDefault().removeDebugEventListener(this); + DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); + super.dispose(); + } + + public void launchesAdded(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED)); + } + + public void launchesRemoved(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED)); + } + + public void launchesChanged(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED)); + } + + public void launchesTerminated(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED)); + } + + private void handleLaunchesEvent(final LaunchesEvent event) { + if (isDisposed()) return; + + // We're in session's executor thread. Re-dispach to VM Adapter + // executor thread and then call root layout node. + try { + getExecutor().execute(new Runnable() { + public void run() { + if (isDisposed()) return; + + IRootVMNode rootLayoutNode = getRootVMNode(); + if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) { + handleEvent(event); + } + }}); + } catch (RejectedExecutionException e) { + // Ignore. This exception could be thrown if the provider is being + // shut down. + } + } + + @Override + protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { + // To optimize view performance when stepping rapidly, skip events that came + // before the last suspended events. However, the debug view can get suspended + // events for different threads, so make sure to skip only the events if they + // were in the same hierarchy as the last suspended event. + if (newEvent instanceof ISuspendedDMEvent && eventToSkip instanceof IDMEvent) { + IDMContext newEventDmc = ((IDMEvent)newEvent).getDMContext(); + IDMContext eventToSkipDmc = ((IDMEvent)eventToSkip).getDMContext(); + + if (newEventDmc.equals(eventToSkipDmc) || DMContexts.isAncestorOf(eventToSkipDmc, newEventDmc)) { + return true; + } + } + + return false; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java index b111973f084..f373511226b 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java @@ -21,6 +21,7 @@ import org.eclipse.dd.dsf.concurrent.DsfRunnable; import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMEvent; import org.eclipse.dd.dsf.debug.service.IRunControl; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; @@ -219,24 +220,19 @@ public abstract class AbstractThreadVMNode extends AbstractDMVMNode public int getDeltaFlags(Object e) { - if (e instanceof IContainerResumedDMEvent || e instanceof IContainerSuspendedDMEvent) { - // No need to react to container events, because the container - // nodes will deal with them. We need this if statement however, - // because the these events extend IResumedDMEvent and - // ISuspendedDMEvent and would trigger the if statement below. + IDMContext dmc = e instanceof IDMEvent ? ((IDMEvent)e).getDMContext() : null; + + if (dmc instanceof IContainerDMContext) { return IModelDelta.NO_CHANGE; } else if (e instanceof IResumedDMEvent && ((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) { return IModelDelta.CONTENT; } else if (e instanceof ISuspendedDMEvent) { - // no change, update happens on FullStackRefreshEvent return IModelDelta.NO_CHANGE; } else if (e instanceof FullStackRefreshEvent) { return IModelDelta.CONTENT; - } else if (e instanceof ISteppingTimedOutEvent && - !(((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) ) - { + } else if (e instanceof ISteppingTimedOutEvent) { return IModelDelta.CONTENT; } else if (e instanceof ModelProxyInstalledEvent) { return IModelDelta.SELECT | IModelDelta.EXPAND; @@ -245,32 +241,51 @@ public abstract class AbstractThreadVMNode extends AbstractDMVMNode } public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { - if(e instanceof IContainerResumedDMEvent || e instanceof IContainerSuspendedDMEvent) { - // No need to react to container events, because the container - // nodes will deal with them. We need this if statement however, - // because the these events extend IResumedDMEvent and - // ISuspendedDMEvent and would trigger the if statement below. - rm.done(); - } else if(e instanceof IResumedDMEvent && - ((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) - { - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + IDMContext dmc = e instanceof IDMEvent ? ((IDMEvent)e).getDMContext() : null; + + if(dmc instanceof IContainerDMContext) { + // The IContainerDMContext sub-classes IExecutionDMContext. + // Also IContainerResumedDMEvent sub-classes IResumedDMEvent and + // IContainerSuspendedDMEvnet sub-classes ISuspendedEvent. + // Because of this relationship, the thread VM node can be called + // with data-model evnets for the containers. This statement + // filters out those event. rm.done(); + } else if(e instanceof IResumedDMEvent) { + // Resumed: + // - If not stepping, update the thread and its content (its stack). + // - If stepping, do nothing to avoid too many updates. If a + // time-out is reached before the step completes, the + // ISteppingTimedOutEvent will trigger a refresh. + if (((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) { + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); + rm.done(); + } } else if (e instanceof ISuspendedDMEvent) { - // no change + // Container suspended. Do nothing here to give the stack the + // priority in updating. The thread will update as a result of + // FullStackRefreshEvent. rm.done(); } else if (e instanceof FullStackRefreshEvent) { - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + // Full-stack refresh event is generated following a suspended event + // and a fixed delay. Refresh the whole thread upon this event. + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); rm.done(); - } else if (e instanceof ISteppingTimedOutEvent && - !(((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) ) - { - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); - // Workaround for bug 233730: we need to add a separate delta node for the state flag in - // order to trigger an update of the run control actions. - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.STATE); + } else if (e instanceof ISteppingTimedOutEvent) { + // Stepping time-out indicates that a step operation is taking + // a long time, and the view needs to be refreshed to show + // the user that the program is running. + parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT); rm.done(); } else if (e instanceof ModelProxyInstalledEvent) { + // Model Proxy install event is generated when the model is first + // populated into the view. This happens when a new debug session + // is started or when the view is first opened. + // In both cases, if there are already threads in the debug model, + // the desired user behavior is to show the threads and to select + // the first thread. + // If the thread is suspended, do not select the thread, instead, + // its top stack frame will be selected. getThreadVMCForModelProxyInstallEvent( parentDelta, new DataRequestMonitor(getExecutor(), rm) { diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/actions/PDATerminateCommand.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/actions/PDATerminateCommand.java index cbfb60c4f75..85abf87d21f 100644 --- a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/actions/PDATerminateCommand.java +++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/actions/PDATerminateCommand.java @@ -22,7 +22,7 @@ import org.eclipse.dd.dsf.service.DsfServicesTracker; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; import org.eclipse.dd.examples.pda.service.PDACommandControl; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; import org.eclipse.dd.examples.pda.ui.PDAUIPlugin; import org.eclipse.debug.core.commands.IDebugCommandRequest; import org.eclipse.debug.core.commands.IEnabledStateRequest; @@ -64,7 +64,7 @@ public class PDATerminateCommand implements ITerminateHandler { // Find the PDA program context in the selected element. If one is not found, // the action should be disabled. IDMVMContext vmc = (IDMVMContext)request.getElements()[0]; - final PDAProgramDMContext pdaProgramCtx = DMContexts.getAncestorOfType(vmc.getDMContext(), PDAProgramDMContext.class); + final PDAVirtualMachineDMContext pdaProgramCtx = DMContexts.getAncestorOfType(vmc.getDMContext(), PDAVirtualMachineDMContext.class); if (pdaProgramCtx == null) { request.setEnabled(false); request.done(); diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDALaunchVMProvider.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDALaunchVMProvider.java index 7a691225bc5..5d269524432 100644 --- a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDALaunchVMProvider.java +++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDALaunchVMProvider.java @@ -11,39 +11,35 @@ *******************************************************************************/ package org.eclipse.dd.examples.pda.ui.viewmodel.launch; -import java.util.concurrent.RejectedExecutionException; - import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractLaunchVMProvider; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StackFramesVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StandardProcessVMNode; -import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; import org.eclipse.dd.dsf.ui.viewmodel.IVMNode; -import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; -import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; -import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchesListener2; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; /** - * View Model provider for the Launch (AKA Debug) view. The PDA debugger is - * single-threaded, so there is no need for a debug target element to be visible - * in the debug view. Therefore the launch VM provider is configured with three nodes: + * View Model provider for the Launch (AKA Debug) view. The launch VM + * provider is configured with three nodes: *
    *
  • LaunchRootVMNode - This is the root of the PDA view model.
  • - *
  • ThreadVMNode - Supplies the PDA program element.
  • + *
  • PDAVirtualMachineVMNode - Supplies the element representing PDA VM
  • + *
  • PDAThreadsVMNode - Supplies the PDA thread elements
  • *
  • StackFramesVMNode - Supplies the stack frame elements.
  • - *
  • StandardProcessVMNode - Supplies elements representing the PDA debugger process.
  • + *
  • StandardProcessVMNode - Supplies elements representing the PDA + * debugger process.
  • *
*/ @SuppressWarnings("restriction") -public class PDALaunchVMProvider extends AbstractDMVMProvider +public class PDALaunchVMProvider extends AbstractLaunchVMProvider implements IDebugEventSetListener, ILaunchesListener2 { @ThreadSafe @@ -55,82 +51,21 @@ public class PDALaunchVMProvider extends AbstractDMVMProvider setRootNode(launchNode); // Launch node is a parent to the processes and program nodes. - IVMNode pdaProgramNode = new PDAProgramVMNode(this, getSession()); + IVMNode pdaVirtualMachineNode = new PDAVirtualMachineVMNode(this, getSession()); IVMNode processesNode = new StandardProcessVMNode(this); - addChildNodes(launchNode, new IVMNode[] { pdaProgramNode, processesNode}); + addChildNodes(launchNode, new IVMNode[] { pdaVirtualMachineNode, processesNode}); - // Stack frames node is under the PDA program node. + // Virtual machine node is under the PDA threads node. + IVMNode threadsNode = new PDAThreadsVMNode(this, getSession()); + addChildNodes(pdaVirtualMachineNode, new IVMNode[] { threadsNode }); + + // Stack frames node is under the PDA threads node. IVMNode stackFramesNode = new StackFramesVMNode(this, getSession()); - addChildNodes(pdaProgramNode, new IVMNode[] { stackFramesNode }); + addChildNodes(threadsNode, new IVMNode[] { stackFramesNode }); // Register the LaunchVM provider as a listener to debug and launch // events. These events are used by the launch and processes nodes. DebugPlugin.getDefault().addDebugEventListener(this); DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); } - - - public void handleDebugEvents(final DebugEvent[] events) { - if (isDisposed()) return; - - // This method may be called on any thread. Switch to the - // view model executor thread before processing. - try { - getExecutor().execute(new Runnable() { - public void run() { - if (isDisposed()) return; - - for (final DebugEvent event : events) { - handleEvent(event); - } - }}); - } catch (RejectedExecutionException e) { - // Ignore. This exception could be thrown if the view model is being - // shut down. - } - } - - @Override - public void dispose() { - DebugPlugin.getDefault().removeDebugEventListener(this); - DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); - super.dispose(); - } - - public void launchesAdded(ILaunch[] launches) { - handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED)); - } - - public void launchesRemoved(ILaunch[] launches) { - handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED)); - } - - public void launchesChanged(ILaunch[] launches) { - handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED)); - } - - public void launchesTerminated(ILaunch[] launches) { - handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED)); - } - - private void handleLaunchesEvent(final LaunchesEvent event) { - if (isDisposed()) return; - - // This method also may be called on any thread. Switch to the - // view model executor thread before processing. - try { - getExecutor().execute(new Runnable() { - public void run() { - if (isDisposed()) return; - - IRootVMNode rootLayoutNode = getRootVMNode(); - if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) { - handleEvent(event); - } - }}); - } catch (RejectedExecutionException e) { - // Ignore. This exception could be thrown if the view model is being - // shut down. - } - } } diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAProgramVMNode.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAProgramVMNode.java deleted file mode 100644 index e8fe38e0334..00000000000 --- a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAProgramVMNode.java +++ /dev/null @@ -1,354 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2008 Wind River Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Wind River Systems - initial API and implementation - * Ericsson - Modified for multi threaded functionality - *******************************************************************************/ -package org.eclipse.dd.examples.pda.ui.viewmodel.launch; - -import java.util.concurrent.RejectedExecutionException; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; -import org.eclipse.dd.dsf.concurrent.DsfRunnable; -import org.eclipse.dd.dsf.concurrent.ImmediateExecutor; -import org.eclipse.dd.dsf.concurrent.RequestMonitor; -import org.eclipse.dd.dsf.datamodel.IDMContext; -import org.eclipse.dd.dsf.datamodel.IDMEvent; -import org.eclipse.dd.dsf.debug.service.IRunControl; -import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData; -import org.eclipse.dd.dsf.debug.service.IRunControl.IResumedDMEvent; -import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; -import org.eclipse.dd.dsf.service.DsfSession; -import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor; -import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMContext; -import org.eclipse.dd.dsf.ui.viewmodel.IVMNode; -import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; -import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; -import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; -import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; -import org.eclipse.dd.examples.pda.PDAPlugin; -import org.eclipse.dd.examples.pda.launch.PDALaunch; -import org.eclipse.dd.examples.pda.service.PDACommandControl; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; -import org.eclipse.dd.examples.pda.service.PDAStartedEvent; -import org.eclipse.debug.core.ILaunch; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; -import org.eclipse.debug.ui.DebugUITools; -import org.eclipse.debug.ui.IDebugUIConstants; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.ui.IMemento; - -/** - * View Model node representing a PDA program. - */ -@SuppressWarnings("restriction") -public class PDAProgramVMNode extends AbstractDMVMNode - implements IElementLabelProvider, IElementMementoProvider -{ - // View model context representing a terminated PDA program. - // It's purpose is to show a terminated program in the debug view - // even after the DSF session is terminated. - // - // Note: this context does not implement the IDMVMContext - // interfaces, as it does not use an IDMContext as its root. - // - // To implement comparison methods, this contexts uses the - // VM node object, such that two terminated program contexts - // from the same instance of VM node will be equal. - private static class TerminatedProgramVMContext extends AbstractVMContext { - TerminatedProgramVMContext(IVMNode node) { - super(node); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof TerminatedProgramVMContext) { - TerminatedProgramVMContext context = (TerminatedProgramVMContext)obj; - return getVMNode().equals(context.getVMNode()); - } - return false; - } - - @Override - public int hashCode() { - return getVMNode().hashCode(); - } - } - - public PDAProgramVMNode(AbstractDMVMProvider provider, DsfSession session) { - super(provider, session, IExecutionDMContext.class); - } - - @Override - public void update(IHasChildrenUpdate[] updates) { - for (IHasChildrenUpdate update : updates) { - // Check if the launch is initialized. PDA program element should - // be shown only if the launch has completed initializing. - PDALaunch launch = findLaunchInPath(update.getElementPath()); - update.setHasChilren(launch != null && launch.isInitialized()); - update.done(); - } - } - - @Override - public void update(IChildrenCountUpdate[] updates) { - for (IChildrenCountUpdate update : updates) { - // Check if the launch is initialized. PDA program element should - // be shown only if the launch has completed initializing. - PDALaunch launch = findLaunchInPath(update.getElementPath()); - if (launch != null && launch.isInitialized()) { - update.setChildCount(1); - } else { - update.setChildCount(0); - } - update.done(); - } - } - - @Override - public void update(IChildrenUpdate[] updates) { - for (IChildrenUpdate update : updates) { - PDALaunch launch = findLaunchInPath(update.getElementPath()); - if (launch != null && launch.isInitialized() && launch.isShutDown()) { - // If the debug session has been shut down, add a dummy - // VM context representing the PDA thread. - update.setChild(new TerminatedProgramVMContext(this), 0); - update.done(); - } else { - super.update(new IChildrenUpdate[] { update }); - } - } - } - - @Override - protected void updateElementsInSessionThread(final IChildrenUpdate update) { - // Get the instance of the service. Note that there is no race condition - // in getting the service since this method is called only in the - // service executor thread. - final PDACommandControl commandControl = getServicesTracker().getService(PDACommandControl.class); - - // Check if the service is available. If it is not, no elements are - // updated. - if (commandControl == null) { - handleFailedUpdate(update); - return; - } - - update.setChild(createVMContext(commandControl.getProgramDMContext()), 0); - update.done(); - } - - public void update(final ILabelUpdate[] updates) { - for (final ILabelUpdate update : updates) { - if (update.getElement() instanceof TerminatedProgramVMContext) { - // If the element is a terminated program, update the label - // in the View Model thread. - updateTerminatedThreadLabel(update); - } else { - // If the element is the PDA Program context, try to switch - // to the DSF session thread before updating the label. - try { - getSession().getExecutor().execute(new DsfRunnable() { - public void run() { - updateProgramLabelInSessionThread(update); - }}); - } catch (RejectedExecutionException e) { - // Acceptable race condition: DSF session terminated. - handleFailedUpdate(update); - } - } - } - } - - @ConfinedToDsfExecutor("getSession().getExecutor()") - private void updateProgramLabelInSessionThread(final ILabelUpdate update) { - // Get a reference to the run control service. - final IRunControl runControl = getServicesTracker().getService(IRunControl.class); - if (runControl == null) { - handleFailedUpdate(update); - return; - } - - // Find the PDA program context. - final PDAProgramDMContext programCtx = - findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAProgramDMContext.class); - - // Call service to get current program state - final boolean isSuspended = runControl.isSuspended(programCtx); - - // Set the program icon based on the running state of the program. - String imageKey = null; - if (isSuspended) { - imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED; - } else { - imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING; - } - update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0); - - // Retrieve the last state change reason - runControl.getExecutionData( - programCtx, - new ViewerDataRequestMonitor(ImmediateExecutor.getInstance(), update) - { - @Override - public void handleCompleted(){ - // If the request failed, fail the udpate. - if (!isSuccess()) { - handleFailedUpdate(update); - return; - } - - // Compose the thread name string. - final StringBuilder builder = new StringBuilder(); - - builder.append("PDA ["); - builder.append(programCtx.getProgram()); - builder.append("]"); - - if(isSuspended) { - builder.append(" (Suspended"); - } else { - builder.append(" (Running"); - } - // Reason will be null before ContainerSuspendEvent is fired - if(getData().getStateChangeReason() != null) { - builder.append(" : "); - builder.append(getData().getStateChangeReason()); - } - builder.append(")"); - update.setLabel(builder.toString(), 0); - update.done(); - } - }); - } - - private void updateTerminatedThreadLabel(ILabelUpdate update) { - update.setLabel(" PDA [" + getProgramName(update) + "]", 0); - update.setImageDescriptor(DebugUITools.getImageDescriptor(IDebugUIConstants.IMG_OBJS_DEBUG_TARGET_TERMINATED), 0); - update.done(); - } - - private String getProgramName(IViewerUpdate update) { - // Retrieve the program name from the launch object in the update path. - String program = "unknown program"; - ILaunch launch = findLaunchInPath(update.getElementPath()); - if (launch != null) { - try { - program = launch.getLaunchConfiguration().getAttribute(PDAPlugin.ATTR_PDA_PROGRAM, program); - } catch (CoreException e) { - // Ignore, label will revert to default. - } - } - return program; - } - - private PDALaunch findLaunchInPath(TreePath path) { - for (int i = 0; i < path.getSegmentCount(); i++) { - if (path.getSegment(i) instanceof PDALaunch) { - return (PDALaunch)path.getSegment(i); - } - } - return null; - } - - public int getDeltaFlags(Object e) { - if(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) { - return IModelDelta.STATE; - } - if (e instanceof PDAStartedEvent) { - return IModelDelta.EXPAND | IModelDelta.SELECT; - } - return IModelDelta.NO_CHANGE; - } - - public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) { - if(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) { - // If a suspended/resumed event is received, just update the - // state of the program. StackFramesVMNode will take care of - // refreshing the stack frames. - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.STATE); - } - if (e instanceof PDAStartedEvent) { - // When debug session is started expand and select the program. - // If the program hits a breakpoint, the top stack frame will then - // be selected. - parentDelta.addNode(createVMContext(((PDAStartedEvent)e).getDMContext()), IModelDelta.EXPAND | IModelDelta.SELECT); - } - rm.done(); - } - - /* - * (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[]) - */ - private String produceProgramElementName( String viewName , PDAProgramDMContext execCtx ) { - return "PDA." + execCtx.getProgram(); //$NON-NLS-1$ - } - - private final String MEMENTO_NAME = "PDAPROGRAM_MEMENTO_NAME"; //$NON-NLS-1$ - - public void compareElements(IElementCompareRequest[] requests) { - - for ( IElementCompareRequest request : requests ) { - - Object element = request.getElement(); - IMemento memento = request.getMemento(); - String mementoName = memento.getString(MEMENTO_NAME); - - if (mementoName != null) { - if (element instanceof IDMVMContext) { - - IDMContext dmc = ((IDMVMContext)element).getDMContext(); - - if ( dmc instanceof PDAProgramDMContext) { - - String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAProgramDMContext) dmc ); - request.setEqual( elementName.equals( mementoName ) ); - } - } - } - request.done(); - } - } - - /* - * (non-Javadoc) - * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[]) - */ - public void encodeElements(IElementMementoRequest[] requests) { - - for ( IElementMementoRequest request : requests ) { - - Object element = request.getElement(); - IMemento memento = request.getMemento(); - - if (element instanceof IDMVMContext) { - - IDMContext dmc = ((IDMVMContext)element).getDMContext(); - - if ( dmc instanceof PDAProgramDMContext) { - - String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAProgramDMContext) dmc ); - memento.putString(MEMENTO_NAME, elementName); - } - } - request.done(); - } - } -} diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAThreadsVMNode.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAThreadsVMNode.java new file mode 100644 index 00000000000..d1d1750c858 --- /dev/null +++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAThreadsVMNode.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + * Ericsson - Modified for multi threaded functionality + *******************************************************************************/ +package org.eclipse.dd.examples.pda.ui.viewmodel.launch; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractThreadVMNode; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.dd.examples.pda.service.PDARunControl; +import org.eclipse.dd.examples.pda.service.PDAThreadDMContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.ui.IMemento; + + +/** + * View model node supplying the PDA thread elements. It extends + * the base threads node and adds label and memento generation. + */ +@SuppressWarnings("restriction") +public class PDAThreadsVMNode extends AbstractThreadVMNode + implements IElementLabelProvider, IElementMementoProvider +{ + public PDAThreadsVMNode(AbstractDMVMProvider provider, DsfSession session) { + super(provider, session); + } + + + @Override + protected void updateLabelInSessionThread(ILabelUpdate[] updates) { + for (final ILabelUpdate update : updates) { + final PDARunControl runControl = getServicesTracker().getService(PDARunControl.class); + if ( runControl == null ) { + handleFailedUpdate(update); + continue; + } + + final PDAThreadDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAThreadDMContext.class); + + String imageKey = null; + if (getServicesTracker().getService(IRunControl.class).isSuspended(dmc)) { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED; + } else { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING; + } + update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0); + + // Find the Reason for the State + runControl.getExecutionData(dmc, + new ViewerDataRequestMonitor(getSession().getExecutor(), update) { + @Override + public void handleCompleted(){ + if (!isSuccess()) { + handleFailedUpdate(update); + return; + } + + // We're in a new dispatch cycle, and we have to check whether the + // service reference is still valid. + final PDARunControl runControl = getServicesTracker().getService(PDARunControl.class); + if ( runControl == null ) { + handleFailedUpdate(update); + return; + } + + final StateChangeReason reason = getData().getStateChangeReason(); + + // Create Labels of type Thread[GDBthreadId]RealThreadID/Name (State: Reason) + // Thread[1] 3457 (Suspended:BREAKPOINT) + final StringBuilder builder = new StringBuilder(); + builder.append("Thread "); + builder.append(dmc.getID()); + if(getServicesTracker().getService(IRunControl.class).isSuspended(dmc)) + builder.append(" (Suspended"); + else + builder.append(" (Running"); + // Reason will be null before ContainerSuspendEvent is fired + if(reason != null) { + builder.append(" : "); + builder.append(reason); + } + builder.append(")"); + update.setLabel(builder.toString(), 0); + update.done(); + } + }); + + } + } + + private String produceThreadElementName(String viewName, PDAThreadDMContext execCtx) { + return "Thread." + execCtx.getID(); + } + + private static final String MEMENTO_NAME = "THREAD_MEMENTO_NAME"; + + /* + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[]) + */ + public void compareElements(IElementCompareRequest[] requests) { + for ( IElementCompareRequest request : requests ) { + Object element = request.getElement(); + IMemento memento = request.getMemento(); + String mementoName = memento.getString(MEMENTO_NAME); + if (mementoName != null) { + if (element instanceof IDMVMContext) { + IDMContext dmc = ((IDMVMContext)element).getDMContext(); + if ( dmc instanceof PDAThreadDMContext) { + String elementName = produceThreadElementName( + request.getPresentationContext().getId(), (PDAThreadDMContext) dmc ); + request.setEqual( elementName.equals( mementoName ) ); + } + } + } + request.done(); + } + } + + /* + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[]) + */ + public void encodeElements(IElementMementoRequest[] requests) { + for ( IElementMementoRequest request : requests ) { + Object element = request.getElement(); + IMemento memento = request.getMemento(); + if (element instanceof IDMVMContext) { + IDMContext dmc = ((IDMVMContext)element).getDMContext(); + if ( dmc instanceof PDAThreadDMContext) { + String elementName = produceThreadElementName( request.getPresentationContext().getId(), (PDAThreadDMContext) dmc ); + memento.putString(MEMENTO_NAME, elementName); + } + } + request.done(); + } + } + +} diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java new file mode 100644 index 00000000000..4a31e8e2acc --- /dev/null +++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + * Wind River Systems - Factored out AbstractContainerVMNode + *******************************************************************************/ + +package org.eclipse.dd.examples.pda.ui.viewmodel.launch; + + +import org.eclipse.dd.dsf.concurrent.ImmediateExecutor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractContainerVMNode; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor; +import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.dd.examples.pda.service.PDACommandControl; +import org.eclipse.dd.examples.pda.service.PDAStartedEvent; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.ui.IMemento; + + +/** + * View Model node representing a PDA virtual machine. It extends + * the base container node and adds label and memento generation. + */ +@SuppressWarnings("restriction") +public class PDAVirtualMachineVMNode extends AbstractContainerVMNode + implements IElementMementoProvider +{ + + + public PDAVirtualMachineVMNode(AbstractDMVMProvider provider, DsfSession session) { + super(provider, session); + } + + @Override + protected void updateElementsInSessionThread(IChildrenUpdate update) { + // Get the instance of the service. Note that there is no race condition + // in getting the service since this method is called only in the + // service executor thread. + final PDACommandControl commandControl = getServicesTracker().getService(PDACommandControl.class); + + // Check if the service is available. If it is not, no elements are + // updated. + if (commandControl == null) { + handleFailedUpdate(update); + return; + } + + update.setChild(createVMContext(commandControl.getVirtualMachineDMContext()), 0); + update.done(); + } + + + @Override + protected void updateLabelInSessionThread(final ILabelUpdate update) { + // Get a reference to the run control service. + final IRunControl runControl = getServicesTracker().getService(IRunControl.class); + if (runControl == null) { + handleFailedUpdate(update); + return; + } + + // Find the PDA program context. + final PDAVirtualMachineDMContext programCtx = + findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAVirtualMachineDMContext.class); + + // Call service to get current program state + final boolean isSuspended = runControl.isSuspended(programCtx); + + // Set the program icon based on the running state of the program. + String imageKey = null; + if (isSuspended) { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED; + } else { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING; + } + update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0); + + // Retrieve the last state change reason + runControl.getExecutionData( + programCtx, + new ViewerDataRequestMonitor(ImmediateExecutor.getInstance(), update) + { + @Override + public void handleCompleted(){ + // If the request failed, fail the udpate. + if (!isSuccess()) { + handleFailedUpdate(update); + return; + } + + // Compose the thread name string. + final StringBuilder builder = new StringBuilder(); + + builder.append("PDA ["); + builder.append(programCtx.getProgram()); + builder.append("]"); + + if(isSuspended) { + builder.append(" (Suspended"); + } else { + builder.append(" (Running"); + } + // Reason will be null before ContainerSuspendEvent is fired + if(getData().getStateChangeReason() != null) { + builder.append(" : "); + builder.append(getData().getStateChangeReason()); + } + builder.append(")"); + update.setLabel(builder.toString(), 0); + update.done(); + } + }); + } + +/* @Override + public int getDeltaFlags(Object e) { + if (e instanceof PDAStartedEvent) { + return IModelDelta.EXPAND | IModelDelta.SELECT; + } + return super.getDeltaFlags(e); + } + + @Override + public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + if (e instanceof PDAStartedEvent) { + // When debug session is started expand and select the program. + // If the program hits a breakpoint, the top stack frame will then + // be selected. + parentDelta.addNode(createVMContext(((PDAStartedEvent)e).getDMContext()), IModelDelta.EXPAND | IModelDelta.SELECT); + rm.done(); + } else { + super.buildDelta(e, parentDelta, nodeOffset, rm); + } + } +*/ + + private String produceProgramElementName( String viewName , PDAVirtualMachineDMContext execCtx ) { + return "PDA." + execCtx.getProgram(); //$NON-NLS-1$ + } + + private final String MEMENTO_NAME = "PDAPROGRAM_MEMENTO_NAME"; //$NON-NLS-1$ + + public void compareElements(IElementCompareRequest[] requests) { + + for ( IElementCompareRequest request : requests ) { + + Object element = request.getElement(); + IMemento memento = request.getMemento(); + String mementoName = memento.getString(MEMENTO_NAME); + + if (mementoName != null) { + if (element instanceof IDMVMContext) { + + IDMContext dmc = ((IDMVMContext)element).getDMContext(); + + if ( dmc instanceof PDAVirtualMachineDMContext) { + + String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAVirtualMachineDMContext) dmc ); + request.setEqual( elementName.equals( mementoName ) ); + } + } + } + request.done(); + } + } + + public void encodeElements(IElementMementoRequest[] requests) { + + for ( IElementMementoRequest request : requests ) { + + Object element = request.getElement(); + IMemento memento = request.getMemento(); + + if (element instanceof IDMVMContext) { + + IDMContext dmc = ((IDMVMContext)element).getDMContext(); + + if ( dmc instanceof PDAVirtualMachineDMContext) { + + String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAVirtualMachineDMContext) dmc ); + memento.putString(MEMENTO_NAME, elementName); + } + } + request.done(); + } + } +} diff --git a/plugins/org.eclipse.dd.examples.pda/pdavm/docs/protocol.html b/plugins/org.eclipse.dd.examples.pda/pdavm/docs/protocol.html index 9e2b92749f4..1d79f31a4fc 100644 --- a/plugins/org.eclipse.dd.examples.pda/pdavm/docs/protocol.html +++ b/plugins/org.eclipse.dd.examples.pda/pdavm/docs/protocol.html @@ -20,8 +20,11 @@ Clears any breakpoint set on given line

data

Retrieves data stack information
-   C: data
+   C: data {thread_id}
    R: {value 1}|{value 2}|{value 3}|...|
+    
+Errors:
+   error: invalid thread
 
@@ -29,10 +32,20 @@ Retrieves data stack information Returns from the current frame without executing the rest of instructions.
-   C: drop
+If VM running:
+   C: drop {thread_id}
    R: ok
-   E: resumed drop
-   E: suspended drop
+   E: resumed {thread_id} drop
+   E: suspended {thread_id} drop
+   
+If VM suspended:
+   C: drop {thread_id}
+   R: ok
+   E: vmresumed drop
+   E: vmsuspended {thread_id} drop
+
+Errors:
+   error: invalid thread
 
@@ -40,11 +53,16 @@ Returns from the current frame without executing the rest of instructions. Sets what events cause the execution to stop.
-   C: eval {instruction}%20{parameter}|{instruction}%20{parameter}|...
+   C: eval {thread_id} {instruction}%20{parameter}|{instruction}%20{parameter}|...
    R: ok
-   E: resume client
+   E: resumed {thread_id} client
    E: evalresult result
-   E: suspended eval
+   E: suspended {thread_id} eval
+   
+Errors:
+   error: invalid thread
+   error: cannot evaluate while vm is suspended
+   error: thread running        
 
@@ -72,8 +90,11 @@ Instructs the debugger to exit. Pops the top value from the data stack
-   C: popdata
+   C: popdata {thread_id}
    R: ok
+   
+Errors:
+   error: invalid thread
 
@@ -81,18 +102,27 @@ Pops the top value from the data stack Pushes the given value on top of the data stack.
-   C: pushdata {value}
+   C: pushdata {thread_id} {value}
    R: ok
+   
+Errors:
+   error: invalid thread
 

resume

-Resumes the execution +Resumes the execution of a single thread. Can be issued only if the virtual +machine is running.
-   C: resume
+   C: resume {thread_id}
    R: ok
-   E: resumed client
+   E: resumed {thread_id} client
+   
+Errors:
+   error: invalid thread
+   error: cannot resume thread when vm is suspended
+   error: thread already running
 
@@ -100,11 +130,19 @@ Resumes the execution Sets a breakpoint at given line
-   C: set {line_number}
+Suspend a single thread:
+   C: set {line_number} 0
    R: ok
-   C: resume
-   E: resumed client
-   E: suspended breakpoint line_number
+   C: resume {thread_id}
+   E: resumed {thread_id} client
+   E: suspended {thread_id} breakpoint line_number
+   
+Suspend the VM:
+   C: set {line_number} 1
+   R: ok
+   C: vmresume
+   E: vmresumed client
+   E: vmsuspended {thread_id} breakpoint line_number
 
@@ -112,8 +150,11 @@ Sets a breakpoint at given line Sets a data value in the data stack at the given location
-   C: setdata {index} {value}
+   C: setdata {thread_id} {index} {value}
    R: ok
+   
+Errors:
+   error: invalid thread
 
@@ -121,8 +162,11 @@ Sets a data value in the data stack at the given location Sets a variable value
-   C: setvar {frame_number} {variable} {value}
+   C: setvar {thread_id} {frame_number} {variable} {value}
    R: ok
+   
+Errors:
+   error: invalid thread
 
@@ -130,8 +174,11 @@ Sets a variable value Retrieves command stack information
-   C: stack
-   R: {file}|{line}|{function}|{var_1}|{var_2}|...{file}|{line}|{function}|{var_1}|{var_2}|......
+   C: stack {thread_id}
+   R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#...
+   
+Errors:
+   error: invalid thread
 
@@ -139,10 +186,20 @@ Retrieves command stack information Executes next instruction
-   C: step
+If VM running:
+   C: step {thread_id}
    R: ok
-   E: resumed step
-   E: suspended step
+   E: resumed {thread_id} client
+   E: suspended {thread_id} step
+   
+If VM suspended:
+   C: step {thread_id}
+   R: ok
+   E: vmresumed client
+   E: vmsuspended {thread_id} step
+   
+Errors:
+   error: invalid thread
 
@@ -150,29 +207,56 @@ Executes next instruction Executes instructions until the current subroutine is finished
-   C: stepreturn
+If VM running:
+   C: stepreturn {thread_id}
    R: ok
-   E: resumed step
-   E: suspended step
+   E: resumed {thread_id} client
+   E: suspended {thread_id} step
+   
+If VM suspended:
+   C: stepreturn {thread_id}
+   R: ok
+   E: vmresumed client
+   E: vmsuspended {thread_id} step
+   
+Errors:
+   error: invalid thread
 

suspend

-Suspends execution +Suspends execution of a single thread. Can be issued only if the virtual +machine is running.
-   C: suspend
+   C: suspend {thread_id}
    R: ok
-   E: suspended client
+   E: suspended {thread_id} client
+   
+Errors:
+   error: invalid thread
+      error: vm already suspended
+   error: thread already suspended
 
+

threads

+Retrieves the list of active threads + +
+   C: threads
+   R: {thread id} {thread id} ...
+

var

Retrieves variable value
-   C: var {frame_number} {variable_name}
+   C: var  {thread_id} {frame_number} {variable_name}
    R: {variable_value}
+   
+Errors:
+   error: invalid thread
+   error: variable undefined
 
@@ -194,5 +278,31 @@ The watch_operation value can be:
  • 2 - write watch
  • 3 - both, etc.
  • + + +

    vmresume

    +Resumes the execution of the whole virtual machine + +
    +   C: vmresume
    +   R: ok
    +   E: vmresumed client
    +   
    +Errors:
    +   error: vm already running
    +
    + +

    vmsuspend

    +Suspends the execution of the whole virtual machine + +
    +   C: vmsuspend
    +   R: ok
    +   E: vmsuspended client
    +   
    +Errors:
    +   error: thread already suspended
    +
    + diff --git a/plugins/org.eclipse.dd.examples.pda/pdavm/src/org/eclipse/dd/examples/pdavm/PDAVirtualMachine.java b/plugins/org.eclipse.dd.examples.pda/pdavm/src/org/eclipse/dd/examples/pdavm/PDAVirtualMachine.java index d371f00c686..443bad80bcb 100644 --- a/plugins/org.eclipse.dd.examples.pda/pdavm/src/org/eclipse/dd/examples/pdavm/PDAVirtualMachine.java +++ b/plugins/org.eclipse.dd.examples.pda/pdavm/src/org/eclipse/dd/examples/pdavm/PDAVirtualMachine.java @@ -38,55 +38,111 @@ public class PDAVirtualMachine { public Object pop() { return isEmpty() ? 0 : remove(size() - 1); } - + public void push(Object value) { add(value); } } class Args { - private final String[] fArgs; + final String[] fArgs; + int next = 0; + Args(String[] args) { fArgs = args; } - + String getNextStringArg() { if (fArgs.length > next) { return fArgs[next++]; } return ""; } - + int getNextIntArg() { String arg = getNextStringArg(); try { return Integer.parseInt(arg); - } catch (NumberFormatException e) {} + } catch (NumberFormatException e) { + } return 0; } - + Object getNextIntOrStringArg() { String arg = getNextStringArg(); try { return Integer.parseInt(arg); - } catch (NumberFormatException e) {} - return arg; + } catch (NumberFormatException e) { + } + return arg; + } + + PDAThread getThreadArg() { + int id = getNextIntArg(); + return fThreads.get(id); } } - /** The push down automata data stack (the data stack). */ - private final Stack fStack = new Stack(); + class PDAThread { + final int fID; + /** The push down automata data stack (the data stack). */ + final Stack fStack = new Stack(); + + /** + * PDAThread copy of the code. It can differ from the program if + * performing an evaluation. + */ + String[] fThreadCode; + + /** PDAThread copy of the labels. */ + Map fThreadLabels; + + /** The stack of stack frames (the control stack) */ + final List fFrames = new LinkedList(); + + /** Current stack frame (not includced in fFrames) */ + Frame fCurrentFrame; + + /** + * The run flag is true if the thread is running. If the run flag is + * false, the thread exits the next time the main instruction loop runs. + */ + boolean fRun = true; + + String fSuspend = null; + + boolean fStep = false; + + boolean fStepReturn = false; + + int fSavedPC; + + boolean fPerformingEval = false; + + PDAThread(int id, String function, int pc) { + fID = id; + fCurrentFrame = new Frame(function, pc); + fThreadCode = fCode; + fThreadLabels = fLabels; + } + } + + final Map fThreads = new LinkedHashMap(); + + int fNextThreadId = 1; + + private boolean fStarted = true; /** - * The code is stored as an array of strings, each line of - * the source file being one entry in the array. + * The code is stored as an array of strings, each line of the source file + * being one entry in the array. */ - private String[] fCode; + final String[] fCode; /** A mapping of labels to indicies in the code array */ - private Map fLabels = new HashMap(); - + final Map fLabels; + /** Each stack frame is a mapping of variable names to values. */ class Frame extends LinkedHashMap { /** @@ -95,80 +151,68 @@ public class PDAVirtualMachine { final String fFunction; /** - * The current program counter in the frame - * the pc points to the next instruction to be executed + * The current program counter in the frame the pc points to the next + * instruction to be executed */ int fPC; - public Frame(String function, int pc) { + Frame(String function, int pc) { fFunction = function; fPC = pc; } } - - /** The stack of stack frames (the control stack) */ - private final List fFrames = new LinkedList(); - - /** Current stack frame (not includced in fFrames) */ - private Frame fCurrentFrame = new Frame("main", 0); - - /** - * Breakpoints are stored as a boolean for each line of code - * if the boolean is true, there is a breakpoint on that line - */ - private final Map fBreakpoints = new HashMap(); /** - * The run flag is true if the VM is running. - * If the run flag is false, the VM exits the - * next time the main instruction loop runs. + * Breakpoints are stored per each each line of code. The boolean indicates + * whether the whole VM should suspend or just the triggering thread. */ - private boolean fRun = true; + final Map fBreakpoints = new HashMap(); /** - * The suspend flag is true if the VM should suspend - * running the program and just listen for debug commands. + * The suspend flag is true if the VM should suspend running the program and + * just listen for debug commands. */ - private String fSuspend; + String fSuspendVM; /** Flag indicating whether the debugger is performing a step. */ - private boolean fStep = false; - + boolean fStepVM = false; + /** Flag indicating whether the debugger is performing a step return */ - private boolean fStepReturn = false; + boolean fStepReturnVM = false; - /** Flag indicating whether the started event was sent. */ - private boolean fStarted = true; + int fSteppingThread = 0; /** Name of the pda program being debugged */ - private final String fFilename; + final String fFilename; - /**The command line argument to start a debug session. */ - private final boolean fDebug; + /** The command line argument to start a debug session. */ + final boolean fDebug; /** The port to listen for debug commands on */ - private final int fCommandPort; + final int fCommandPort; - /** Command socket for receiving debug commands and sending command responses */ - private Socket fCommandSocket; + /** + * Command socket for receiving debug commands and sending command responses + */ + Socket fCommandSocket; /** Command socket reader */ - private BufferedReader fCommandReceiveStream; - + BufferedReader fCommandReceiveStream; + /** Command socket write stream. */ - private OutputStream fCommandResponseStream; + OutputStream fCommandResponseStream; /** The port to send debug events to */ - private final int fEventPort; - + final int fEventPort; + /** Event socket */ - private Socket fEventSocket; - + Socket fEventSocket; + /** Event socket and write stream. */ - private OutputStream fEventStream; + OutputStream fEventStream; /** The eventstops table holds which events cause suspends and which do not. */ - private final Map fEventStops = new HashMap(); + final Map fEventStops = new HashMap(); { fEventStops.put("unimpinstr", false); fEventStops.put("nosuchlabel", false); @@ -176,37 +220,35 @@ public class PDAVirtualMachine { /** * The watchpoints table holds watchpoint information. - * variablename_stackframedepth => N - * N = 0 is no watch - * N = 1 is read watch - * N = 2 is write watch - * N = 3 is both, etc. + *

    + * variablename_stackframedepth => N + *

      + *
    • N = 0 is no watch
    • + *
    • N = 1 is read watch
    • + *
    • N = 2 is write watch
    • + *
    • N = 3 is both, etc.
    • */ - private final Map fWatchpoints = new HashMap(); - - public String[] fSavedCode; - public Map fSavedLables; - public int fSavedPC; - + final Map fWatchpoints = new HashMap(); + public static void main(String[] args) { String programFile = args.length >= 1 ? args[0] : null; if (programFile == null) { System.err.println("Error: No program specified"); return; } - + String debugFlag = args.length >= 2 ? args[1] : ""; boolean debug = "-debug".equals(debugFlag); int commandPort = 0; int eventPort = 0; - + if (debug) { String commandPortStr = args.length >= 3 ? args[2] : ""; try { commandPort = Integer.parseInt(commandPortStr); } catch (NumberFormatException e) { System.err.println("Error: Invalid command port"); - return; + return; } String eventPortStr = args.length >= 4 ? args[3] : ""; @@ -214,10 +256,10 @@ public class PDAVirtualMachine { eventPort = Integer.parseInt(eventPortStr); } catch (NumberFormatException e) { System.err.println("Error: Invalid event port"); - return; + return; } } - + PDAVirtualMachine pdaVM = null; try { pdaVM = new PDAVirtualMachine(programFile, debug, commandPort, eventPort); @@ -228,10 +270,10 @@ public class PDAVirtualMachine { } pdaVM.run(); } - - public PDAVirtualMachine(String inputFile, boolean debug, int commandPort, int eventPort) throws IOException{ + + PDAVirtualMachine(String inputFile, boolean debug, int commandPort, int eventPort) throws IOException { fFilename = inputFile; - + // Load all the code into memory FileReader fileReader = new FileReader(inputFile); StringWriter stringWriter = new StringWriter(); @@ -249,37 +291,35 @@ public class PDAVirtualMachine { code.add(stringWriter.toString().trim()); fCode = code.toArray(new String[code.size()]); - mapLabels(); - + fLabels = mapLabels(fCode); + fDebug = debug; fCommandPort = commandPort; fEventPort = eventPort; - if (fDebug) { - fSuspend = "client"; - } } - + /** * Initializes the labels map */ - private void mapLabels() { - fLabels = new HashMap(); - for (int i = 0; i < fCode.length; i++) { - if (fCode[i].length() != 0 && fCode[i].charAt(0) == ':') { - fLabels.put(fCode[i].substring(1), i); + Map mapLabels(String[] code) { + Map labels = new HashMap(); + for (int i = 0; i < code.length; i++) { + if (code[i].length() != 0 && code[i].charAt(0) == ':') { + labels.put(code[i].substring(1), i); } } - + return labels; } - - private void sendCommandResponse(String response) { + + void sendCommandResponse(String response) { try { fCommandResponseStream.write(response.getBytes()); fCommandResponseStream.flush(); - } catch (IOException e) {} + } catch (IOException e) { + } } - private void sendDebugEvent(String event, boolean error) { + void sendDebugEvent(String event, boolean error) { if (fDebug) { try { fEventStream.write(event.getBytes()); @@ -287,18 +327,18 @@ public class PDAVirtualMachine { fEventStream.flush(); } catch (IOException e) { System.err.println("Error: " + e); - fRun = false; + System.exit(1); } } else if (error) { System.err.println("Error: " + event); } } - - private void startDebugger() throws IOException { + + void startDebugger() throws IOException { if (fDebug) { System.out.println("-debug " + fCommandPort + " " + fEventPort); } - + ServerSocket commandServerSocket = new ServerSocket(fCommandPort); fCommandSocket = commandServerSocket.accept(); fCommandReceiveStream = new BufferedReader(new InputStreamReader(fCommandSocket.getInputStream())); @@ -309,32 +349,74 @@ public class PDAVirtualMachine { fEventSocket = eventServerSocket.accept(); fEventStream = new PrintStream(fEventSocket.getOutputStream()); eventServerSocket.close(); - + System.out.println("debug connection accepted"); - - fSuspend = "client"; - sendDebugEvent("started", false); + + fSuspendVM = "client"; } - - public void run() { - while (fRun) { + + void run() { + int id = fNextThreadId++; + fThreads.put(id, new PDAThread(id, "main", 0)); + if (fDebug) { + sendDebugEvent("started " + id, false); + } + + boolean allThreadsSuspended = false; + while (!fThreads.isEmpty()) { checkForBreakpoint(); - if (fSuspend != null) { + + if (fSuspendVM != null) { debugUI(); - } - yieldToDebug(); - String instruction = fCode[fCurrentFrame.fPC]; - fCurrentFrame.fPC++; - doOneInstruction(instruction); - if (fCurrentFrame.fPC > fCode.length) { - fRun = false; - } else if (fStepReturn) { - instruction = fCode[fCurrentFrame.fPC]; - if ("return".equals(instruction)) { - fSuspend = "step"; + } else { + yieldToDebug(allThreadsSuspended); + if (fSuspendVM != null) { + // Received a command to suspend VM, skip executing threads. + continue; } } + + PDAThread[] threadsCopy = fThreads.values().toArray(new PDAThread[fThreads.size()]); + allThreadsSuspended = true; + for (PDAThread thread : threadsCopy) { + if (thread.fSuspend == null) { + allThreadsSuspended = false; + + String instruction = thread.fThreadCode[thread.fCurrentFrame.fPC]; + thread.fCurrentFrame.fPC++; + doOneInstruction(thread, instruction); + if (thread.fCurrentFrame.fPC > thread.fThreadCode.length) { + // Thread reached end of code, exit from the thread. + thread.fRun = false; + } else if (thread.fStepReturn) { + // If this thread is in a step-return operation, check + // if we've returned from a call. + instruction = thread.fThreadCode[thread.fCurrentFrame.fPC]; + if ("return".equals(instruction)) { + // Note: this will only be triggered if the current + // thread also has the fStepReturn flag set. + if (fStepReturnVM) { + fSuspendVM = thread.fID + " step"; + } else { + thread.fSuspend = "step"; + } + } + } + if (!thread.fRun) { + sendDebugEvent("exited " + thread.fID, false); + fThreads.remove(thread.fID); + } else if (thread.fSuspend != null) { + sendDebugEvent("suspended " + thread.fID + " " + thread.fSuspend, false); + thread.fStep = thread.fStepReturn = thread.fPerformingEval = false; + } + } + } + + // Force thread context switch to avoid starving out other + // processes in the system. + Thread.yield(); } + sendDebugEvent("terminated", false); if (fDebug) { try { @@ -347,122 +429,141 @@ public class PDAVirtualMachine { System.out.println("Error: " + e); } } - - } - - private void doOneInstruction(String instr) { - if (instr.startsWith(":")) { - // label - if (fStep) { - fSuspend = "step"; - } - } else if (instr.startsWith("#")) { - // comment - } else { - StringTokenizer tokenizer = new StringTokenizer(instr); - String op = tokenizer.nextToken(); - List tokens = new LinkedList(); - while (tokenizer.hasMoreTokens()) { - tokens.add(tokenizer.nextToken()); - } - Args args = new Args(tokens.toArray(new String[tokens.size()])); - boolean opValid = true; - if (op.equals("add")) iAdd(args); - else if (op.equals("branch_not_zero")) iBranchNotZero(args); - else if (op.equals("call")) iCall(args); - else if (op.equals("dec")) iDec(args); - else if (op.equals("dup")) iDup(args); - else if (op.equals("halt")) iHalt(args); - else if (op.equals("output")) iOutput(args); - else if (op.equals("pop")) iPop(args); - else if (op.equals("push")) iPush(args); - else if (op.equals("return")) iReturn(args); - else if (op.equals("var")) iVar(args); - else if (op.equals("xyzzy")) iInternalEndEval(args); - else { - opValid = false; + } + + void doOneInstruction(PDAThread thread, String instr) { + StringTokenizer tokenizer = new StringTokenizer(instr); + String op = tokenizer.nextToken(); + List tokens = new LinkedList(); + while (tokenizer.hasMoreTokens()) { + tokens.add(tokenizer.nextToken()); + } + Args args = new Args(tokens.toArray(new String[tokens.size()])); + + boolean opValid = true; + if (op.equals("add")) iAdd(thread, args); + else if (op.equals("branch_not_zero")) iBranchNotZero(thread, args); + else if (op.equals("call")) iCall(thread, args); + else if (op.equals("dec")) iDec(thread, args); + else if (op.equals("dup")) iDup(thread, args); + else if (op.equals("exec")) iExec(thread, args); + else if (op.equals("halt")) iHalt(thread, args); + else if (op.equals("output")) iOutput(thread, args); + else if (op.equals("pop")) iPop(thread, args); + else if (op.equals("push")) iPush(thread, args); + else if (op.equals("return")) iReturn(thread, args); + else if (op.equals("var")) iVar(thread, args); + else if (op.equals("xyzzy")) iInternalEndEval(thread, args); + else if (op.startsWith(":")) {} // label + else if (op.startsWith("#")) {} // comment + else { + opValid = false; + } + + if (!opValid) { + sendDebugEvent("unimplemented instruction " + op, true); + if (fEventStops.get("unimpinstr")) { + fSuspendVM = thread.fID + " event unimpinstr"; + thread.fCurrentFrame.fPC--; } - - if (!opValid) { - sendDebugEvent("unimplemented instruction " + op, true); - if (fEventStops.get("unimpinstr")) { - fSuspend = "event unimpinstr"; - fCurrentFrame.fPC--; - } - } else if (fStep) { - fSuspend = "step"; + } else if (thread.fStep) { + if (fStepVM) { + fSuspendVM = thread.fID + " step"; + fStepVM = false; + } else { + thread.fSuspend = "step"; } + thread.fStep = false; } } - - private void checkForBreakpoint() { + + void checkForBreakpoint() { if (fDebug) { - int pc = fCurrentFrame.fPC; - if (!"eval".equals(fSuspend) && fBreakpoints.containsKey(pc) && fBreakpoints.get(pc)) { - fSuspend = "breakpoint " + pc; + for (PDAThread thread : fThreads.values()) { + int pc = thread.fCurrentFrame.fPC; + // Suspend for breakpoint if: + // - the VM is not yet set to suspend, for e.g. as a result of step end, + // - the thread is not yet suspended and is not performing an evaluation + // - the breakpoints table contains a breakpoint for the given line. + if (fSuspendVM == null && + thread.fSuspend == null && !thread.fPerformingEval && + fBreakpoints.containsKey(pc)) + { + if (fBreakpoints.get(pc)) { + fSuspendVM = thread.fID + " breakpoint " + pc; + } else { + thread.fSuspend = "breakpoint " + pc; + thread.fStep = thread.fStepReturn = false; + sendDebugEvent("suspended " + thread.fID + " " + thread.fSuspend, false); + } + } } } } - + /** - * For each instruction, we check the debug co-routine for - * control input. If there is input, we process it. + * After each instruction, we check the debug command channel for control input. If + * there are commands, process them. */ - private void yieldToDebug() { + void yieldToDebug(boolean allThreadsSuspended) { if (fDebug) { String line = ""; try { - if (fCommandReceiveStream.ready()) { + if (allThreadsSuspended || fCommandReceiveStream.ready()) { line = fCommandReceiveStream.readLine(); processDebugCommand(line); } } catch (IOException e) { System.err.println("Error: " + e); - fRun = false; - return; + System.exit(1); } } } - - private void debugUI() { - if (fSuspend == null) { - return; - } - + + /** + * Service the debugger commands while the VM is suspended + */ + void debugUI() { if (!fStarted) { - sendDebugEvent("suspended " + fSuspend, false); + sendDebugEvent("vmsuspended " + fSuspendVM, false); } else { fStarted = false; } + + // Clear all stepping flags. In case the VM suspended while + // a step operation was being performed for the VM or some thread. + fStepVM = fStepReturnVM = false; + for (PDAThread thread : fThreads.values()) { + thread.fSuspend = null; + thread.fStep = thread.fStepReturn = thread.fPerformingEval = false; + } - fStep = false; - fStepReturn = false; - - while (fSuspend != null) { + while (fSuspendVM != null) { String line = ""; try { line = fCommandReceiveStream.readLine(); } catch (IOException e) { System.err.println("Error: " + e); - fRun = false; + System.exit(1); return; } processDebugCommand(line); } - if (fStep) { - sendDebugEvent("resumed step", false); + + if (fStepVM || fStepReturnVM) { + sendDebugEvent("vmresumed step", false); } else { - sendDebugEvent("resumed client", false); + sendDebugEvent("vmresumed client", false); } } - - private void processDebugCommand(String line) { + + void processDebugCommand(String line) { StringTokenizer tokenizer = new StringTokenizer(line.trim()); if (line.length() == 0) { return; } - + String command = tokenizer.nextToken(); List tokens = new LinkedList(); while (tokenizer.hasMoreTokens()) { @@ -471,42 +572,64 @@ public class PDAVirtualMachine { Args args = new Args(tokens.toArray(new String[tokens.size()])); if ("clear".equals(command)) debugClearBreakpoint(args); - else if ("data".equals(command)) debugData(); - else if ("drop".equals(command)) debugDropFrame(); + else if ("data".equals(command)) debugData(args); + else if ("drop".equals(command)) debugDropFrame(args); else if ("eval".equals(command)) debugEval(args); else if ("eventstop".equals(command)) debugEventStop(args); else if ("exit".equals(command)) debugExit(); - else if ("popdata".equals(command)) debugPop(); + else if ("popdata".equals(command)) debugPop(args); else if ("pushdata".equals(command)) debugPush(args); - else if ("resume".equals(command)) debugResume(); + else if ("resume".equals(command)) debugResume(args); else if ("set".equals(command)) debugSetBreakpoint(args); else if ("setdata".equals(command)) debugSetData(args); else if ("setvar".equals(command)) debugSetVariable(args); - else if ("stack".equals(command)) debugStack(); - else if ("step".equals(command)) debugStep(); - else if ("stepreturn".equals(command)) debugStepReturn(); - else if ("suspend".equals(command)) debugSuspend(); + else if ("stack".equals(command)) debugStack(args); + else if ("state".equals(command)) debugState(args); + else if ("step".equals(command)) debugStep(args); + else if ("stepreturn".equals(command)) debugStepReturn(args); + else if ("suspend".equals(command)) debugSuspend(args); + else if ("threads".equals(command)) debugThreads(); else if ("var".equals(command)) debugVar(args); + else if ("vmresume".equals(command)) debugVMResume(); + else if ("vmsuspend".equals(command)) debugVMSuspend(); else if ("watch".equals(command)) debugWatch(args); + else { + sendCommandResponse("error: invalid command\n"); + } } - - private void debugClearBreakpoint(Args args) { + + void debugClearBreakpoint(Args args) { int line = args.getNextIntArg(); - - fBreakpoints.put(line, false); + + fBreakpoints.remove(line); sendCommandResponse("ok\n"); } private static Pattern fPackPattern = Pattern.compile("%([a-fA-F0-9][a-fA-F0-9])"); - private void debugEval(Args args) { + + void debugEval(Args args) { + if (fSuspendVM != null) { + sendCommandResponse("error: cannot evaluate while vm is suspended\n"); + return; + } + + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + + if (thread.fSuspend == null) { + sendCommandResponse("error: thread running\n"); + return; + } StringTokenizer tokenizer = new StringTokenizer(args.getNextStringArg(), "|"); tokenizer.countTokens(); - - fSavedCode = fCode; + int numEvalLines = tokenizer.countTokens(); - fCode = new String[fSavedCode.length + numEvalLines + 1]; - System.arraycopy(fSavedCode, 0, fCode, 0, fSavedCode.length); + thread.fThreadCode = new String[fCode.length + numEvalLines + 1]; + System.arraycopy(fCode, 0, thread.fThreadCode, 0, fCode.length); for (int i = 0; i < numEvalLines; i++) { String line = tokenizer.nextToken(); StringBuffer lineBuf = new StringBuffer(line.length()); @@ -516,123 +639,188 @@ public class PDAVirtualMachine { lineBuf.append(line.substring(lastMatchEnd, matcher.start())); String charCode = line.substring(matcher.start() + 1, matcher.start() + 3); try { - lineBuf.append((char)Integer.parseInt(charCode, 16)); - } catch (NumberFormatException e) {} + lineBuf.append((char) Integer.parseInt(charCode, 16)); + } catch (NumberFormatException e) { + } lastMatchEnd = matcher.end(); } if (lastMatchEnd < line.length()) { lineBuf.append(line.substring(lastMatchEnd)); } - fCode[fSavedCode.length + i] = lineBuf.toString(); + thread.fThreadCode[fCode.length + i] = lineBuf.toString(); } - fCode[fSavedCode.length + numEvalLines] = "xyzzy"; - mapLabels(); + thread.fThreadCode[fCode.length + numEvalLines] = "xyzzy"; + thread.fThreadLabels = mapLabels(fCode); + + thread.fSavedPC = thread.fCurrentFrame.fPC; + thread.fCurrentFrame.fPC = fCode.length; + thread.fPerformingEval = true; - fSavedPC = fCurrentFrame.fPC; - fCurrentFrame.fPC = fSavedCode.length; + thread.fSuspend = null; sendCommandResponse("ok\n"); - - fSuspend = null; + + sendDebugEvent("resumed " + thread.fID + " eval", false); } - - private void debugData() { + + void debugData(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + StringBuffer result = new StringBuffer(); - for (Object val : fStack) { + for (Object val : thread.fStack) { result.append(val); result.append('|'); } result.append('\n'); sendCommandResponse(result.toString()); } - - private void debugDropFrame() { - if (!fFrames.isEmpty()) { - fCurrentFrame = fFrames.remove(fFrames.size() - 1); + + void debugDropFrame(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; } - fCurrentFrame.fPC--; + + if (!thread.fFrames.isEmpty()) { + thread.fCurrentFrame = thread.fFrames.remove(thread.fFrames.size() - 1); + } + thread.fCurrentFrame.fPC--; sendCommandResponse("ok\n"); - sendDebugEvent( "resumed drop", false ); - sendDebugEvent( "suspended drop", false ); + if (fSuspendVM != null) { + sendDebugEvent("vmresumed drop", false); + sendDebugEvent("vmsuspended " + thread.fID + " drop", false); + } else { + sendDebugEvent("resumed " + thread.fID + " drop", false); + sendDebugEvent("suspended " + thread.fID + " drop", false); + } } - - private void debugEventStop(Args args) { + + void debugEventStop(Args args) { String event = args.getNextStringArg(); int stop = args.getNextIntArg(); fEventStops.put(event, stop > 0); sendCommandResponse("ok\n"); } - private void debugExit() { + void debugExit() { sendCommandResponse("ok\n"); - sendDebugEvent( "terminated", false ); + sendDebugEvent("terminated", false); System.exit(0); } - - private void debugPop() { - fStack.pop(); - sendCommandResponse("ok\n"); - } - - private void debugPush(Args args) { - Object val = args.getNextIntOrStringArg(); - fStack.push(val); + + void debugPop(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + + thread.fStack.pop(); sendCommandResponse("ok\n"); } - private void debugResume() { - fSuspend = null; - sendCommandResponse("ok\n"); - } - - private void debugSetBreakpoint(Args args) { - int line = args.getNextIntArg(); + void debugPush(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } - fBreakpoints.put(line, true); + Object val = args.getNextIntOrStringArg(); + thread.fStack.push(val); sendCommandResponse("ok\n"); } - - private void debugSetData(Args args) { + + void debugResume(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + if (fSuspendVM != null) { + sendCommandResponse("error: cannot resume thread when vm is suspended\n"); + return; + } + if (thread.fSuspend == null) { + sendCommandResponse("error: thread already running\n"); + return; + } + + thread.fSuspend = null; + sendDebugEvent("resumed " + thread.fID + " client", false); + + sendCommandResponse("ok\n"); + } + + void debugSetBreakpoint(Args args) { + int line = args.getNextIntArg(); + int stopVM = args.getNextIntArg(); + + fBreakpoints.put(line, stopVM != 0); + sendCommandResponse("ok\n"); + } + + void debugSetData(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + int offset = args.getNextIntArg(); Object val = args.getNextIntOrStringArg(); - if (offset < fStack.size()) { - fStack.set(offset, val); + if (offset < thread.fStack.size()) { + thread.fStack.set(offset, val); } else { - fStack.add(0, val); + thread.fStack.add(0, val); } sendCommandResponse("ok\n"); } - private void debugSetVariable(Args args) { + void debugSetVariable(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + int sfnumber = args.getNextIntArg(); String var = args.getNextStringArg(); Object val = args.getNextIntOrStringArg(); - - if (sfnumber > fFrames.size()) { - fCurrentFrame.put(var, val); + + if (sfnumber >= thread.fFrames.size()) { + thread.fCurrentFrame.put(var, val); } else { - fFrames.get(sfnumber).put(var, val); + thread.fFrames.get(sfnumber).put(var, val); } - sendCommandResponse("ok\n"); + sendCommandResponse("ok\n"); } - - private void debugStack() { + + void debugStack(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + StringBuffer result = new StringBuffer(); - for (Frame frame : fFrames) { + for (Frame frame : thread.fFrames) { result.append(printFrame(frame)); result.append('#'); } - result.append(printFrame(fCurrentFrame)); + result.append(printFrame(thread.fCurrentFrame)); result.append('\n'); sendCommandResponse(result.toString()); } - /** - * The stack frame output is: - * frame # frame # frame ... - * where each frame is: + * The stack frame output is: frame # frame # frame ... where each frame is: * filename | line number | function name | var | var | var | var ... */ private String printFrame(Frame frame) { @@ -649,161 +837,288 @@ public class PDAVirtualMachine { return buf.toString(); } - private void debugStep() { - // set suspend to 0 to allow the debug loop to exit back to - // the instruction loop and thus run an instruction. However, - // we want to come back to the debug loop right away, so the - // step flag is set to true which will cause the suspend flag - // to get set to true when we get to the next instruction. - fStep = true; - fSuspend = null; - sendCommandResponse("ok\n"); + void debugState(Args args) { + PDAThread thread = args.getThreadArg(); + String response = null; + if (thread == null) { + response = fSuspendVM == null ? "running" : fSuspendVM; + } else if (fSuspendVM != null) { + response = "vm"; + } else { + response = thread.fSuspend == null ? "running" : thread.fSuspend; + } + sendCommandResponse(response + "\n"); + } + + void debugStep(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + + // Set suspend to null to allow the debug loop to exit back to the + // instruction loop and thus run an instruction. However, we want to + // come back to the debug loop right away, so the step flag is set to + // true which will cause the suspend flag to get set to true when we + // get to the next instruction. + if (fSuspendVM != null) { + // All threads are suspended, so suspend all threads again when + // step completes. + fSuspendVM = null; + fStepVM = true; + // Also mark the thread that initiated the step to mark it as + // the triggering thread when suspending. + thread.fStep = true; + } else { + if (thread.fSuspend == null) { + sendCommandResponse("error: thread already running\n"); + return; + } + thread.fSuspend = null; + thread.fStep = true; + sendDebugEvent("resumed " + thread.fID + " step", false); + } + sendCommandResponse("ok\n"); } - private void debugStepReturn() { - fStepReturn = true; - fSuspend = null; - sendCommandResponse("ok\n"); + void debugStepReturn(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + + if (fSuspendVM != null) { + fSuspendVM = null; + fStepReturnVM = true; + thread.fStepReturn = true; + } else { + if (thread.fSuspend == null) { + sendCommandResponse("error: thread running\n"); + return; + } + thread.fSuspend = null; + thread.fStepReturn = true; + sendDebugEvent("resumed " + thread.fID + " step", false); + } + sendCommandResponse("ok\n"); } - - private void debugSuspend() { - fSuspend = "client"; - sendCommandResponse("ok\n"); + + void debugSuspend(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + if (fSuspendVM != null) { + sendCommandResponse("error: vm already suspended\n"); + return; + } + if (thread.fSuspend != null) { + sendCommandResponse("error: thread already suspended\n"); + return; + } + + thread.fSuspend = "client"; + sendDebugEvent("suspended " + thread.fID + " client", false); + sendCommandResponse("ok\n"); } - - private void debugVar(Args args) { + + void debugThreads() { + StringBuffer response = new StringBuffer(); + for (int threadId : fThreads.keySet()) { + response.append(threadId); + response.append(' '); + } + sendCommandResponse(response.toString().trim() + "\n"); + } + + void debugVar(Args args) { + PDAThread thread = args.getThreadArg(); + if (thread == null) { + sendCommandResponse("error: invalid thread\n"); + return; + } + int sfnumber = args.getNextIntArg(); String var = args.getNextStringArg(); - if (sfnumber >= fFrames.size()) { - sendCommandResponse(fCurrentFrame.get(var).toString() + "\n"); + Frame frame = sfnumber >= thread.fFrames.size() + ? thread.fCurrentFrame : thread.fFrames.get(sfnumber); + + Object val = frame.get(var); + if (val == null) { + sendCommandResponse("error: variable undefined\n"); } else { - sendCommandResponse(fFrames.get(sfnumber).get(var).toString() + "\n"); + sendCommandResponse(val.toString() + "\n"); } } - - private void debugWatch(Args args) { + + void debugVMResume() { + if (fSuspendVM == null) { + sendCommandResponse("error: vm already running\n"); + return; + } + + fSuspendVM = null; + sendCommandResponse("ok\n"); + } + + void debugVMSuspend() { + if (fSuspendVM != null) { + sendCommandResponse("error: vm already suspended\n"); + return; + } + + fSuspendVM = "client"; + sendCommandResponse("ok\n"); + } + + void debugWatch(Args args) { String funcAndVar = args.getNextStringArg(); int flags = args.getNextIntArg(); fWatchpoints.put(funcAndVar, flags); - sendCommandResponse("ok\n"); + sendCommandResponse("ok\n"); } - private void iAdd(Args args) { - Object val1 = fStack.pop(); - Object val2 = fStack.pop(); + void iAdd(PDAThread thread, Args args) { + Object val1 = thread.fStack.pop(); + Object val2 = thread.fStack.pop(); if (val1 instanceof Integer && val2 instanceof Integer) { - int intVal1 = ((Integer)val1).intValue(); - int intVal2 = ((Integer)val2).intValue(); - fStack.push(intVal1 + intVal2); + int intVal1 = ((Integer) val1).intValue(); + int intVal2 = ((Integer) val2).intValue(); + thread.fStack.push(intVal1 + intVal2); } else { - fStack.push(-1); + thread.fStack.push(-1); } } - private void iBranchNotZero(Args args) { - Object val = fStack.pop(); - if( val instanceof Integer && ((Integer)val).intValue() != 0 ) { + void iBranchNotZero(PDAThread thread, Args args) { + Object val = thread.fStack.pop(); + if (val instanceof Integer && ((Integer) val).intValue() != 0) { String label = args.getNextStringArg(); - if (fLabels.containsKey(label)) { - fCurrentFrame.fPC = fLabels.get(label); + if (thread.fThreadLabels.containsKey(label)) { + thread.fCurrentFrame.fPC = thread.fThreadLabels.get(label); } else { sendDebugEvent("no such label " + label, true); - if( fEventStops.get("nosuchlabel") ) { - fSuspend = "event nosuchlabel"; - fStack.push(val); - fCurrentFrame.fPC--; + if (fEventStops.get("nosuchlabel")) { + fSuspendVM = thread.fID + " event nosuchlabel"; + thread.fStack.push(val); + thread.fCurrentFrame.fPC--; } - } + } } } - private void iCall(Args args) { + void iCall(PDAThread thread, Args args) { String label = args.getNextStringArg(); - if (fLabels.containsKey(label)) { - fFrames.add(fCurrentFrame); - fCurrentFrame = new Frame(label, fLabels.get(label)); + if (thread.fThreadLabels.containsKey(label)) { + thread.fFrames.add(thread.fCurrentFrame); + thread.fCurrentFrame = new Frame(label, thread.fThreadLabels.get(label)); } else { sendDebugEvent("no such label " + label, true); - if( fEventStops.get("nosuchlabel") ) { - fSuspend = "event nosuchlabel"; - fCurrentFrame.fPC--; + if (fEventStops.get("nosuchlabel")) { + fSuspendVM = thread.fID + " event nosuchlabel"; + thread.fCurrentFrame.fPC--; } - } + } } - private void iDec(Args args) { - Object val = fStack.pop(); + void iDec(PDAThread thread, Args args) { + Object val = thread.fStack.pop(); if (val instanceof Integer) { - val = new Integer( ((Integer)val).intValue() - 1 ); + val = new Integer(((Integer) val).intValue() - 1); } - fStack.push(val); - } + thread.fStack.push(val); + } - private void iDup(Args args) { - Object val = fStack.pop(); - fStack.push(val); - fStack.push(val); - } + void iDup(PDAThread thread, Args args) { + Object val = thread.fStack.pop(); + thread.fStack.push(val); + thread.fStack.push(val); + } + + void iExec(PDAThread thread, Args args) { + String label = args.getNextStringArg(); + if (fLabels.containsKey(label)) { + int id = fNextThreadId++; + fThreads.put(id, new PDAThread(id, label, fLabels.get(label))); + sendDebugEvent("started " + id, false); + } else { + sendDebugEvent("no such label " + label, true); + if (fEventStops.get("nosuchlabel")) { + thread.fSuspend = "event nosuchlabel"; + thread.fCurrentFrame.fPC--; + } + } + } - private void iHalt(Args args) { - fRun = false; - } + void iHalt(PDAThread thread, Args args) { + thread.fRun = false; + } - private void iOutput(Args args) { - System.out.println(fStack.pop()); - } + void iOutput(PDAThread thread, Args args) { + System.out.println(thread.fStack.pop()); + } - private void iPop(Args args) { + void iPop(PDAThread thread, Args args) { String arg = args.getNextStringArg(); if (arg.startsWith("$")) { String var = arg.substring(1); - fCurrentFrame.put(var, fStack.pop()); - String key = fCurrentFrame.fFunction + "::" + var; + thread.fCurrentFrame.put(var, thread.fStack.pop()); + String key = thread.fCurrentFrame.fFunction + "::" + var; if (fWatchpoints.containsKey(key) && (fWatchpoints.get(key) & 2) != 0) { - fSuspend = "watch write " + key; + fSuspendVM = thread.fID + " watch write " + key; } } else { - fStack.pop(); + thread.fStack.pop(); } - } + } - private void iPush(Args args) { + void iPush(PDAThread thread, Args args) { String arg = args.getNextStringArg(); if (arg.startsWith("$")) { String var = arg.substring(1); - Object val = fCurrentFrame.containsKey(var) ? fCurrentFrame.get(var) : ""; - fStack.push(val); - String key = fCurrentFrame.fFunction + "::" + var; + Object val = thread.fCurrentFrame.containsKey(var) ? thread.fCurrentFrame.get(var) : ""; + thread.fStack.push(val); + String key = thread.fCurrentFrame.fFunction + "::" + var; if (fWatchpoints.containsKey(key) && (fWatchpoints.get(key) & 1) != 0) { - fSuspend = "watch read " + key; + fSuspendVM = thread.fID + " watch read " + key; } } else { Object val = arg; try { val = Integer.parseInt(arg); - } catch (NumberFormatException e) {} - fStack.push(val); + } catch (NumberFormatException e) { + } + thread.fStack.push(val); } - } - private void iReturn(Args args) { - if (!fFrames.isEmpty()) { - fCurrentFrame = fFrames.remove(fFrames.size() - 1); - } } - private void iVar(Args args) { - String var = args.getNextStringArg(); - fCurrentFrame.put(var, 0); - } - private void iInternalEndEval(Args args) { - Object result = fStack.pop(); - fCode = fSavedCode; - fLabels = fSavedLables; - fCurrentFrame.fPC = fSavedPC; + void iReturn(PDAThread thread, Args args) { + if (!thread.fFrames.isEmpty()) { + thread.fCurrentFrame = thread.fFrames.remove(thread.fFrames.size() - 1); + } else { + // Execution returned from the top frame, which means this thread + // should exit. + thread.fRun = false; + } + } + + void iVar(PDAThread thread, Args args) { + String var = args.getNextStringArg(); + thread.fCurrentFrame.put(var, 0); + } + + void iInternalEndEval(PDAThread thread, Args args) { + Object result = thread.fStack.pop(); + thread.fThreadCode = fCode; + thread.fThreadLabels = fLabels; + thread.fCurrentFrame.fPC = thread.fSavedPC; sendDebugEvent("evalresult " + result, false); - fSuspend = "eval"; - } - - + thread.fSuspend = "eval"; + thread.fPerformingEval = false; + } + } diff --git a/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest3.pda b/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest3.pda index a9fcfc2a853..5aecdc5e6e0 100644 --- a/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest3.pda +++ b/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest3.pda @@ -8,4 +8,6 @@ add call zippy add output +push 1 +branch_not_zero swishy halt diff --git a/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest9.pda b/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest9.pda new file mode 100644 index 00000000000..336a251d9ab --- /dev/null +++ b/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest9.pda @@ -0,0 +1,23 @@ +push 5 +:thread_create +exec foo +dec +dup +branch_not_zero thread_create +push finished +output +halt +:foo +push thread_created +output +call inner +halt +:inner +var b +call inner2 +push 2 +return +:inner2 +var c +push 3 +return diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDAServicesInitSequence.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDAServicesInitSequence.java index ec15010f9fc..1de0b2aa12f 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDAServicesInitSequence.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDAServicesInitSequence.java @@ -78,7 +78,7 @@ public class PDAServicesInitSequence extends Sequence { bpmService.initialize(new RequestMonitor(getExecutor(), requestMonitor) { @Override protected void handleSuccess() { - bpmService.startTrackingBreakpoints(fCommandControl.getProgramDMContext(), requestMonitor); + bpmService.startTrackingBreakpoints(fCommandControl.getVirtualMachineDMContext(), requestMonitor); } }); } @@ -107,7 +107,7 @@ public class PDAServicesInitSequence extends Sequence { new Step() { @Override public void execute(RequestMonitor requestMonitor) { - fRunControl.resume(fCommandControl.getProgramDMContext(), requestMonitor); + fRunControl.resume(fCommandControl.getVirtualMachineDMContext(), requestMonitor); } }, }; diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABreakpoints.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABreakpoints.java index 01f3259de65..a98a5686a06 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABreakpoints.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABreakpoints.java @@ -51,7 +51,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints final Integer fLine; - public BreakpointDMContext(String sessionId, PDAProgramDMContext commandControlCtx, Integer line) { + public BreakpointDMContext(String sessionId, PDAVirtualMachineDMContext commandControlCtx, Integer line) { super(sessionId, new IDMContext[] { commandControlCtx }); fLine = line; } @@ -81,7 +81,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints final String fFunction; final String fVariable; - public WatchpointDMContext(String sessionId, PDAProgramDMContext commandControlCtx, String function, + public WatchpointDMContext(String sessionId, PDAVirtualMachineDMContext commandControlCtx, String function, String variable) { super(sessionId, new IDMContext[] { commandControlCtx }); @@ -164,7 +164,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints public void getBreakpoints(final IBreakpointsTargetDMContext context, final DataRequestMonitor rm) { // Validate the context - if (!fCommandControl.getProgramDMContext().equals(context)) { + if (!fCommandControl.getVirtualMachineDMContext().equals(context)) { PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoints target context"); return; } @@ -193,7 +193,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints // breakpoints mediator, which was called with the program context // in the services initialization sequence. So checking if // programCtx != null is mostly a formality. - PDAProgramDMContext programCtx = DMContexts.getAncestorOfType(context, PDAProgramDMContext.class); + PDAVirtualMachineDMContext programCtx = DMContexts.getAncestorOfType(context, PDAVirtualMachineDMContext.class); if (programCtx != null) { doInsertBreakpoint(programCtx, attributes, rm); } else { @@ -209,7 +209,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints } } - private void doInsertBreakpoint(PDAProgramDMContext programCtx, final Map attributes, final DataRequestMonitor rm) + private void doInsertBreakpoint(PDAVirtualMachineDMContext programCtx, final Map attributes, final DataRequestMonitor rm) { // Compare the program path in the breakpoint with the path in the PDA // program context. Only insert the breakpoint if the program matches. @@ -230,7 +230,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints // installed already. PDA can only track a single breakpoint at a // given line, attempting to set the second breakpoint should fail. final BreakpointDMContext breakpointCtx = - new BreakpointDMContext(getSession().getId(), fCommandControl.getProgramDMContext(), line); + new BreakpointDMContext(getSession().getId(), fCommandControl.getVirtualMachineDMContext(), line); if (fBreakpoints.contains(breakpointCtx)) { PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already set"); return; @@ -244,7 +244,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints // still being processed here. fBreakpoints.add(breakpointCtx); fCommandControl.queueCommand( - new PDASetBreakpointCommand(fCommandControl.getProgramDMContext(), line), + new PDASetBreakpointCommand(fCommandControl.getVirtualMachineDMContext(), line, false), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -286,7 +286,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints // installed already. PDA can only track a single watchpoint for a given // function::variable, attempting to set the second breakpoint should fail. final WatchpointDMContext watchpointCtx = - new WatchpointDMContext(getSession().getId(), fCommandControl.getProgramDMContext(), function, variable); + new WatchpointDMContext(getSession().getId(), fCommandControl.getVirtualMachineDMContext(), function, variable); if (fBreakpoints.contains(watchpointCtx)) { PDAPlugin.failRequest(rm, REQUEST_FAILED, "Watchpoint already set"); return; @@ -310,7 +310,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints // still being processed here. fBreakpoints.add(watchpointCtx); fCommandControl.queueCommand( - new PDAWatchCommand(fCommandControl.getProgramDMContext(), function, variable, watchOperation), + new PDAWatchCommand(fCommandControl.getVirtualMachineDMContext(), function, variable, watchOperation), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -350,7 +350,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints fBreakpoints.remove(bpCtx); fCommandControl.queueCommand( - new PDAClearBreakpointCommand(fCommandControl.getProgramDMContext(), bpCtx.fLine), + new PDAClearBreakpointCommand(fCommandControl.getVirtualMachineDMContext(), bpCtx.fLine), new DataRequestMonitor(getExecutor(), rm)); } @@ -360,7 +360,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints // Watchpoints are cleared using the same command, but with a "no watch" operation fCommandControl.queueCommand( new PDAWatchCommand( - fCommandControl.getProgramDMContext(), bpCtx.fFunction, bpCtx.fVariable, PDAWatchCommand.WatchOperation.NONE), + fCommandControl.getVirtualMachineDMContext(), bpCtx.fFunction, bpCtx.fVariable, PDAWatchCommand.WatchOperation.NONE), new DataRequestMonitor(getExecutor(), rm)); } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDACommandControl.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDACommandControl.java index f2089254e58..b4121dc4799 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDACommandControl.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDACommandControl.java @@ -89,7 +89,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon private boolean fTerminated = false; // Data Model context of this command control. - private PDAProgramDMContext fDMContext; + private PDAVirtualMachineDMContext fDMContext; // Synchronous listeners for commands and events. private final List fCommandListeners = new ArrayList(); @@ -137,12 +137,12 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon private void doInitialize(final RequestMonitor rm) { // Create the control's data model context. - fDMContext = new PDAProgramDMContext(getSession().getId(), fProgram); + fDMContext = new PDAVirtualMachineDMContext(getSession().getId(), fProgram); // Add a listener for PDA events to track the started/terminated state. addEventListener(new IEventListener() { public void eventReceived(Object output) { - if ("started".equals(output)) { + if ("started 1".equals(output)) { setStarted(); } else if ("terminated".equals(output)) { setTerminated(); @@ -247,7 +247,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon @Override protected IStatus run(IProgressMonitor monitor) { while (!isTerminated()) { - synchronized(fTxCommands) { + synchronized (fTxCommands) { try { // Remove command from send queue. final CommandHandle commandHandle = fTxCommands.take(); @@ -483,10 +483,10 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon /** * Return the PDA Debugger top-level Data Model context. - * @see PDAProgramDMContext + * @see PDAVirtualMachineDMContext */ @ThreadSafe - public PDAProgramDMContext getProgramDMContext() { + public PDAVirtualMachineDMContext getVirtualMachineDMContext() { return fDMContext; } @@ -498,7 +498,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon processQueues(); // Issue a data model event. - getSession().dispatchEvent(new PDAStartedEvent(getProgramDMContext()), getProperties()); + getSession().dispatchEvent(new PDAStartedEvent(getVirtualMachineDMContext()), getProperties()); } /** @@ -520,7 +520,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon processQueues(); // Issue a data model event. - getSession().dispatchEvent(new PDATerminatedEvent(getProgramDMContext()), getProperties()); + getSession().dispatchEvent(new PDATerminatedEvent(getVirtualMachineDMContext()), getProperties()); } } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAExpressions.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAExpressions.java index 29fbfa38061..5d6be6e8da2 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAExpressions.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAExpressions.java @@ -214,11 +214,12 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions { // Create an expression based on the given context and string expression. // The PDA debugger can only evaluate variables as expressions and only // in context of a frame. + PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(ctx, PDAThreadDMContext.class); IFrameDMContext frameCtx = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class); - if (frameCtx != null) { + if (threadCtx != null && frameCtx != null) { return new ExpressionDMContext(getSession().getId(), frameCtx, expression); } else { - // If a frame cannot be found in context, return an "invalid" + // If the thread or a frame cannot be found in context, return an "invalid" // expression context, because a null return value is not allowed. // Evaluating an invalid expression context will always yield an // error. @@ -276,6 +277,7 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions { { final ExpressionDMContext exprCtx = DMContexts.getAncestorOfType(formattedCtx, ExpressionDMContext.class); if (exprCtx != null) { + final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class); final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class); // First retrieve the stack depth, needed to properly calculate @@ -290,7 +292,11 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions { // Send the command to evaluate the variable. fCommandCache.execute( - new PDAVarCommand(fCommandControl.getProgramDMContext(), frameId, exprCtx.getExpression()), + new PDAVarCommand( + fCommandControl.getVirtualMachineDMContext(), + threadCtx.getID(), + frameId, + exprCtx.getExpression()), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -310,6 +316,7 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions { final RequestMonitor rm) { if (exprCtx instanceof ExpressionDMContext) { + final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class); final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class); // Similarly to retrieving the variable, retrieve the @@ -324,7 +331,12 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions { // Send the "write" command to PDA debugger fCommandCache.execute( - new PDASetVarCommand(fCommandControl.getProgramDMContext(), frameId, exprCtx.getExpression(), exprValue), + new PDASetVarCommand( + fCommandControl.getVirtualMachineDMContext(), + threadCtx.getID(), + frameId, + exprCtx.getExpression(), + exprValue), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARegisters.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARegisters.java index df4bb44007e..08944cfa3a1 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARegisters.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARegisters.java @@ -101,7 +101,7 @@ public class PDARegisters extends AbstractDsfService implements IRegisters { * @see org.eclipse.dd.dsf.debug.service.IRegisters#getRegisterGroups(org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) */ public void getRegisterGroups(IDMContext ctx, DataRequestMonitor rm ) { - PDAProgramDMContext execDmc = DMContexts.getAncestorOfType(ctx, PDAProgramDMContext.class); + PDAVirtualMachineDMContext execDmc = DMContexts.getAncestorOfType(ctx, PDAVirtualMachineDMContext.class); if (execDmc == null) { rm.setStatus( new Status( IStatus.ERROR , PDAPlugin.PLUGIN_ID , INVALID_HANDLE , "Container context not found", null ) ) ; //$NON-NLS-1$ rm.done(); @@ -738,7 +738,7 @@ public class PDARegisters extends AbstractDsfService implements IRegisters { private int fGroupNo; private String fGroupName; - public MIRegisterGroupDMC(PDARegisters service, PDAProgramDMContext execDmc, int groupNo, String groupName) { + public MIRegisterGroupDMC(PDARegisters service, PDAVirtualMachineDMContext execDmc, int groupNo, String groupName) { super(service.getSession().getId(), new IDMContext[] { execDmc }); fGroupNo = groupNo; fGroupName = groupName; diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARunControl.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARunControl.java index 75efec10170..01102212817 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARunControl.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARunControl.java @@ -11,7 +11,11 @@ *******************************************************************************/ package org.eclipse.dd.examples.pda.service; +import java.util.Arrays; import java.util.Hashtable; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; @@ -26,10 +30,13 @@ import org.eclipse.dd.dsf.service.AbstractDsfService; import org.eclipse.dd.dsf.service.DsfServiceEventHandler; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.examples.pda.PDAPlugin; +import org.eclipse.dd.examples.pda.service.commands.AbstractPDACommand; import org.eclipse.dd.examples.pda.service.commands.PDACommandResult; import org.eclipse.dd.examples.pda.service.commands.PDAResumeCommand; import org.eclipse.dd.examples.pda.service.commands.PDAStepCommand; -import org.eclipse.dd.examples.pda.service.commands.PDASuspendCommand; +import org.eclipse.dd.examples.pda.service.commands.PDAStepReturnCommand; +import org.eclipse.dd.examples.pda.service.commands.PDAVMResumeCommand; +import org.eclipse.dd.examples.pda.service.commands.PDAVMSuspendCommand; import org.osgi.framework.BundleContext; @@ -55,7 +62,112 @@ public class PDARunControl extends AbstractDsfService // The purpose of this pattern is to allow clients that listen to service // events and track service state, to be perfectly in sync with the service // state. + + static final private IExecutionDMContext[] EMPTY_TRIGGERING_CONTEXTS_ARRAY = new IExecutionDMContext[0]; + + @Immutable + private static class ThreadResumedEvent extends AbstractDMEvent + implements IResumedDMEvent + { + private final StateChangeReason fReason; + + ThreadResumedEvent(PDAThreadDMContext ctx, StateChangeReason reason) { + super(ctx); + fReason = reason; + } + + public StateChangeReason getReason() { + return fReason; + } + + @Override + public String toString() { + return "THREAD RESUMED: " + getDMContext() + " (" + fReason + ")"; + } + } + @Immutable + private static class VMResumedEvent extends AbstractDMEvent + implements IContainerResumedDMEvent + { + private final StateChangeReason fReason; + + VMResumedEvent(PDAVirtualMachineDMContext ctx, StateChangeReason reason) { + super(ctx); + fReason = reason; + } + + public StateChangeReason getReason() { + return fReason; + } + + public IExecutionDMContext[] getTriggeringContexts() { + return EMPTY_TRIGGERING_CONTEXTS_ARRAY; + } + + @Override + public String toString() { + return "VM RESUMED: (" + fReason + ")"; + } + } + + @Immutable + private static class ThreadSuspendedEvent extends AbstractDMEvent + implements ISuspendedDMEvent + { + private final StateChangeReason fReason; + + ThreadSuspendedEvent(PDAThreadDMContext ctx, StateChangeReason reason) { + super(ctx); + fReason = reason; + } + + public StateChangeReason getReason() { + return fReason; + } + + @Override + public String toString() { + return "THREAD SUSPENDED: " + getDMContext() + " (" + fReason + ")"; + } + } + + @Immutable + private static class VMSuspendedEvent extends AbstractDMEvent + implements IContainerSuspendedDMEvent + { + private final StateChangeReason fReason; + + final private IExecutionDMContext[] fTriggeringThreads; + + VMSuspendedEvent(PDAVirtualMachineDMContext ctx, PDAThreadDMContext threadCtx, StateChangeReason reason) { + super(ctx); + fReason = reason; + if (threadCtx != null) { + fTriggeringThreads = new IExecutionDMContext[] { threadCtx }; + } else { + fTriggeringThreads = EMPTY_TRIGGERING_CONTEXTS_ARRAY; + } + } + + public StateChangeReason getReason() { + return fReason; + } + + public IExecutionDMContext[] getTriggeringContexts() { + return fTriggeringThreads; + } + + + @Override + public String toString() { + return "THREAD SUSPENDED: " + getDMContext() + + " (" + fReason + + ", trigger = " + Arrays.asList(fTriggeringThreads) + + ")"; + } + } + @Immutable private static class ExecutionDMData implements IExecutionDMData { private final StateChangeReason fReason; @@ -65,62 +177,63 @@ public class PDARunControl extends AbstractDsfService public StateChangeReason getStateChangeReason() { return fReason; } } - @Immutable - private static class ResumedEvent extends AbstractDMEvent - implements IResumedDMEvent + private static class ThreadStartedEvent extends AbstractDMEvent + implements IStartedDMEvent { - private final String fPDAEvent; - - ResumedEvent(IExecutionDMContext ctx, String pdaEvent) { - super(ctx); - fPDAEvent = pdaEvent; - } - - public StateChangeReason getReason() { - if (fPDAEvent.startsWith("resumed breakpoint") || fPDAEvent.startsWith("suspended watch")) { - return StateChangeReason.BREAKPOINT; - } else if (fPDAEvent.equals("resumed step") || fPDAEvent.equals("resumed drop")) { - return StateChangeReason.STEP; - } else if (fPDAEvent.equals("resumed client")) { - return StateChangeReason.USER_REQUEST; - } else { - return StateChangeReason.UNKNOWN; - } + ThreadStartedEvent(PDAThreadDMContext threadCtx) { + super(threadCtx); } } - @Immutable - private static class SuspendedEvent extends AbstractDMEvent - implements ISuspendedDMEvent + private static class ThreadExitedEvent extends AbstractDMEvent + implements IExitedDMEvent { - private final String fPDAEvent; - - SuspendedEvent(IExecutionDMContext ctx, String pdaEvent) { - super(ctx); - fPDAEvent = pdaEvent; - } - - public StateChangeReason getReason() { - if (fPDAEvent.startsWith("suspended breakpoint") || fPDAEvent.startsWith("suspended watch")) { - return StateChangeReason.BREAKPOINT; - } else if (fPDAEvent.equals("suspended step") || fPDAEvent.equals("suspended drop")) { - return StateChangeReason.STEP; - } else if (fPDAEvent.equals("suspended client")) { - return StateChangeReason.USER_REQUEST; - } else { - return StateChangeReason.UNKNOWN; - } + ThreadExitedEvent(PDAThreadDMContext threadCtx) { + super(threadCtx); } } - + // Services private PDACommandControl fCommandControl; - - // State flags - private boolean fSuspended = true; - private boolean fResumePending = false; - private boolean fStepping = false; - private StateChangeReason fStateChangeReason; + + // Reference to the virtual machine data model context + private PDAVirtualMachineDMContext fDMContext; + + // VM state flags + private boolean fVMSuspended = true; + private boolean fVMResumePending = false; + private boolean fVMSuspendPending = false; + private boolean fVMStepping = false; + private StateChangeReason fVMStateChangeReason; + + // Threads' state data + private static class ThreadInfo { + final PDAThreadDMContext fContext; + boolean fSuspended = false; + boolean fResumePending = false; + boolean fSuspendPending = false; + boolean fStepping = false; + StateChangeReason fStateChangeReason = StateChangeReason.UNKNOWN; + + ThreadInfo(PDAThreadDMContext context) { + fContext = context; + } + + @Override + public String toString() { + return fContext.toString() + " (" + + (fSuspended ? "SUSPENDED, " : "SUSPENDED, ") + + fStateChangeReason + + (fResumePending ? ", RESUME_PENDING, " : "") + + (fSuspendPending ? ", SUSPEND_PENDING, " : "") + + (fStepping ? ", SUSPEND_PENDING, " : "") + + ")"; + + } + } + + private Map fThreads = new LinkedHashMap(); + public PDARunControl(DsfSession session) { super(session); @@ -142,14 +255,21 @@ public class PDARunControl extends AbstractDsfService } private void doInitialize(final RequestMonitor rm) { + // Cache a reference to the command control and the virtual machine context fCommandControl = getServicesTracker().getService(PDACommandControl.class); + fDMContext = fCommandControl.getVirtualMachineDMContext(); - // Add ourselves as a listener to PDA events, to catch suspended/resumed - // events. + // Create the main thread context. + fThreads.put( + 1, + new ThreadInfo(new PDAThreadDMContext(getSession().getId(), fDMContext, 1))); + + // Add the run control service as a listener to PDA events, to catch + // suspended/resumed/started/exited events from the command control. fCommandControl.addEventListener(this); - // Add ourselves as a listener to service events, in order to process - // our own suspended/resumed events. + // Add the run control service as a listener to service events as well, + // in order to process our own suspended/resumed/started/exited events. getSession().addServiceEventListener(this, null); // Register the service with OSGi @@ -182,42 +302,137 @@ public class PDARunControl extends AbstractDsfService if (!(output instanceof String)) return; String event = (String)output; + int nameEnd = event.indexOf(' '); + nameEnd = nameEnd == -1 ? event.length() : nameEnd; + String eventName = event.substring(0, nameEnd); + + PDAThreadDMContext thread = null; + StateChangeReason reason = StateChangeReason.UNKNOWN; + if (event.length() > nameEnd + 1) { + if ( Character.isDigit(event.charAt(nameEnd + 1)) ) { + int threadIdEnd = event.indexOf(' ', nameEnd + 1); + threadIdEnd = threadIdEnd == -1 ? event.length() : threadIdEnd; + try { + int threadId = Integer.parseInt(event.substring(nameEnd + 1, threadIdEnd)); + if (fThreads.containsKey(threadId)) { + thread = fThreads.get(threadId).fContext; + } else { + // In case where a suspended event follows directly a + // started event, a thread may not be in the list of + // known threads yet. In this case create the + // thread context based on the ID. + thread = new PDAThreadDMContext(getSession().getId(), fDMContext, threadId); + } + } catch (NumberFormatException e) {} + if (threadIdEnd + 1 < event.length()) { + reason = parseStateChangeReason(event.substring(threadIdEnd + 1)); + } + } else { + reason = parseStateChangeReason(event.substring(nameEnd + 1)); + } + } + // Handle PDA debugger suspended/resumed events and issue the // corresponding Data Model events. Do not update the state // information until we start dispatching the service events. - if (event.startsWith("suspended")) { - IDMEvent dmEvent = new SuspendedEvent(fCommandControl.getProgramDMContext(), event); - getSession().dispatchEvent(dmEvent, getProperties()); - } else if (event.startsWith("resumed")) { - IDMEvent dmEvent = new ResumedEvent(fCommandControl.getProgramDMContext(), event); + IDMEvent dmEvent = null; + if (eventName.equals("suspended") && thread != null) { + dmEvent = new ThreadSuspendedEvent(thread, reason); + } else if (eventName.equals("resumed") && thread != null) { + dmEvent = new ThreadResumedEvent(thread, reason); + } else if (event.startsWith("vmsuspended")) { + dmEvent = new VMSuspendedEvent(fDMContext, thread, reason); + } else if (event.startsWith("vmresumed")) { + dmEvent = new VMResumedEvent(fDMContext, reason); + } else if (event.startsWith("started") && thread != null) { + dmEvent = new ThreadStartedEvent(thread); + } else if (event.startsWith("exited") && thread != null) { + dmEvent = new ThreadExitedEvent(thread); + } + + if (dmEvent != null) { getSession().dispatchEvent(dmEvent, getProperties()); } } + private StateChangeReason parseStateChangeReason(String reasonString) { + if (reasonString.startsWith("breakpoint") || reasonString.startsWith("watch")) { + return StateChangeReason.BREAKPOINT; + } else if (reasonString.equals("step") || reasonString.equals("drop")) { + return StateChangeReason.STEP; + } else if (reasonString.equals("client")) { + return StateChangeReason.USER_REQUEST; + } else if (reasonString.startsWith("event")) { + return StateChangeReason.SIGNAL; + } else { + return StateChangeReason.UNKNOWN; + } + + } @DsfServiceEventHandler - public void eventDispatched(ResumedEvent e) { - // This service should be the first to receive the ResumedEvent, - // (before any other listeners are called). Here, update the - // service state information based on the the resumed event. - fSuspended = false; - fResumePending = false; - fStateChangeReason = e.getReason(); - fStepping = e.getReason().equals(StateChangeReason.STEP); + public void eventDispatched(ThreadResumedEvent e) { + ThreadInfo info = fThreads.get(((PDAThreadDMContext)e.getDMContext()).getID()); + if (info != null) { + info.fSuspended = false; + info.fResumePending = false; + info.fStateChangeReason = e.getReason(); + info.fStepping = e.getReason().equals(StateChangeReason.STEP); + } } @DsfServiceEventHandler - public void eventDispatched(SuspendedEvent e) { - // This service should be the first to receive the SuspendedEvent also, - // (before any other listeners are called). Here, update the - // service state information based on the the suspended event. - fStateChangeReason = e.getReason(); - fResumePending = false; - fSuspended = true; - fStepping = false; + public void eventDispatched(VMResumedEvent e) { + fVMSuspended = false; + fVMResumePending = false; + fVMStateChangeReason = e.getReason(); + fVMStepping = e.getReason().equals(StateChangeReason.STEP); + for (ThreadInfo info : fThreads.values()) { + info.fSuspended = false; + info.fStateChangeReason = StateChangeReason.CONTAINER; + info.fStepping = false; + } + } + + @DsfServiceEventHandler + public void eventDispatched(ThreadSuspendedEvent e) { + ThreadInfo info = fThreads.get(((PDAThreadDMContext)e.getDMContext()).getID()); + if (info != null) { + info.fSuspended = true; + info.fSuspendPending = false; + info.fStateChangeReason = e.getReason(); + info.fStepping = e.getReason().equals(StateChangeReason.STEP); + } } + + @DsfServiceEventHandler + public void eventDispatched(VMSuspendedEvent e) { + fVMStateChangeReason = e.getReason(); + fVMSuspendPending = false; + fVMSuspended = true; + fVMStepping = false; + List triggeringContexts = Arrays.asList(e.getTriggeringContexts()); + for (ThreadInfo info : fThreads.values()) { + info.fSuspended = true; + info.fStateChangeReason = triggeringContexts.contains(info.fContext) + ? StateChangeReason.STEP : StateChangeReason.CONTAINER; + info.fStepping = false; + } + } + + @DsfServiceEventHandler + public void eventDispatched(ThreadStartedEvent e) { + PDAThreadDMContext threadCtx = (PDAThreadDMContext)e.getDMContext(); + fThreads.put(threadCtx.getID(), new ThreadInfo(threadCtx)); + } + + @DsfServiceEventHandler + public void eventDispatched(ThreadExitedEvent e) { + PDAThreadDMContext threadCtx = (PDAThreadDMContext)e.getDMContext(); + fThreads.remove(threadCtx.getID()); + } public void canResume(IExecutionDMContext context, DataRequestMonitor rm) { rm.setData(doCanResume(context)); @@ -225,7 +440,34 @@ public class PDARunControl extends AbstractDsfService } private boolean doCanResume(IExecutionDMContext context) { - return isSuspended(context) && !fResumePending; + if (context instanceof PDAThreadDMContext) { + PDAThreadDMContext threadContext = (PDAThreadDMContext)context; + // Threads can be resumed only if the VM is not suspended. + if (!fVMSuspended) { + ThreadInfo state = fThreads.get(threadContext.getID()); + if (state != null) { + return state.fSuspended && !state.fResumePending; + } + } + } else { + return fVMSuspended && !fVMResumePending; + } + return false; + } + + private boolean doCanStep(IExecutionDMContext context, StepType stepType) { + if (stepType == StepType.STEP_OVER || stepType == StepType.STEP_RETURN) { + if (context instanceof PDAThreadDMContext) { + PDAThreadDMContext threadContext = (PDAThreadDMContext)context; + // Only threads can be stepped. But they can be stepped + // while the VM is suspended or when just the thread is suspended. + ThreadInfo state = fThreads.get(threadContext.getID()); + if (state != null) { + return state.fSuspended && !state.fResumePending; + } + } + } + return false; } public void canSuspend(IExecutionDMContext context, DataRequestMonitor rm) { @@ -234,35 +476,86 @@ public class PDARunControl extends AbstractDsfService } private boolean doCanSuspend(IExecutionDMContext context) { - return !isSuspended(context); + if (context instanceof PDAThreadDMContext) { + PDAThreadDMContext threadContext = (PDAThreadDMContext)context; + // Threads can be resumed only if the VM is not suspended. + if (!fVMSuspended) { + ThreadInfo state = fThreads.get(threadContext.getID()); + if (state != null) { + return !state.fSuspended && state.fSuspendPending; + } + } + } else { + return !fVMSuspended && !fVMSuspendPending; + } + return false; } public boolean isSuspended(IExecutionDMContext context) { - return fSuspended; + if (context instanceof PDAThreadDMContext) { + PDAThreadDMContext threadContext = (PDAThreadDMContext)context; + // Threads can be resumed only if the VM is not suspended. + if (!fVMSuspended) { + ThreadInfo state = fThreads.get(threadContext.getID()); + if (state != null) { + return state.fSuspended; + } + } + } + return fVMSuspended; } public boolean isStepping(IExecutionDMContext context) { - return !isSuspended(context) && fStepping; + if (isSuspended(context)) { + if (context instanceof PDAThreadDMContext) { + PDAThreadDMContext threadContext = (PDAThreadDMContext)context; + // Threads can be resumed only if the VM is not suspended. + if (!fVMStepping) { + ThreadInfo state = fThreads.get(threadContext.getID()); + if (state != null) { + return state.fStepping; + } + } + } + return fVMStepping; + } + return false; } public void resume(IExecutionDMContext context, final RequestMonitor rm) { assert context != null; if (doCanResume(context)) { - fResumePending = true; - fCommandControl.queueCommand( - new PDAResumeCommand(fCommandControl.getProgramDMContext()), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleFailure() { - // If the resume command failed, we no longer - // expect to receive a resumed event. - fResumePending = false; - super.handleFailure(); + if (context instanceof PDAThreadDMContext) { + final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context; + fThreads.get(threadCtx.getID()).fResumePending = true; + fCommandControl.queueCommand( + new PDAResumeCommand(fDMContext, threadCtx.getID()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleFailure() { + ThreadInfo threadState = fThreads.get(threadCtx.getID()); + if (threadState != null) { + threadState.fResumePending = false; + } + super.handleFailure(); + } } - } - ); - }else { + ); + } else { + fVMResumePending = true; + fCommandControl.queueCommand( + new PDAVMResumeCommand(fDMContext), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleFailure() { + fVMResumePending = false; + super.handleFailure(); + } + } + ); + } + } else { PDAPlugin.failRequest(rm, INVALID_STATE, "Given context: " + context + ", is already running."); } } @@ -271,35 +564,79 @@ public class PDARunControl extends AbstractDsfService assert context != null; if (doCanSuspend(context)) { - fCommandControl.queueCommand( - new PDASuspendCommand(fCommandControl.getProgramDMContext()), - new DataRequestMonitor(getExecutor(), rm)); - + if (context instanceof PDAThreadDMContext) { + final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context; + fThreads.get(threadCtx.getID()).fSuspendPending = true; + fCommandControl.queueCommand( + new PDAVMSuspendCommand(fDMContext), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleFailure() { + ThreadInfo threadState = fThreads.get(threadCtx.getID()); + if (threadState != null) { + threadState.fSuspendPending = false; + } + super.handleFailure(); + } + } + ); + } else { + fVMSuspendPending = true; + fCommandControl.queueCommand( + new PDAVMSuspendCommand(fDMContext), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleFailure() { + fVMSuspendPending = false; + super.handleFailure(); + } + } + ); + } } else { PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_STATE, "Given context: " + context + ", is already suspended."); } } public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor rm) { - canResume(context, rm); + rm.setData(doCanStep(context, stepType)); + rm.done(); } public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) { assert context != null; - if (doCanResume(context)) { - fResumePending = true; - fStepping = true; + if (doCanStep(context, stepType)) { + final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context; + final boolean vmWasSuspneded = fVMSuspended; + + if (vmWasSuspneded) { + fVMResumePending = true; + } else { + fThreads.get(threadCtx.getID()).fResumePending = true; + } + AbstractPDACommand stepCommand = + stepType == StepType.STEP_RETURN + ? new PDAStepReturnCommand(fDMContext, threadCtx.getID()) + : new PDAStepCommand(fDMContext, threadCtx.getID()); + + fCommandControl.queueCommand( - new PDAStepCommand(fCommandControl.getProgramDMContext()), + stepCommand, new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleFailure() { // If the step command failed, we no longer // expect to receive a resumed event. - fResumePending = false; - fStepping = false; + if (vmWasSuspneded) { + fVMResumePending = false; + } else { + ThreadInfo threadState = fThreads.get(threadCtx.getID()); + if (threadState != null) { + threadState.fResumePending = false; + } + } } }); @@ -310,11 +647,26 @@ public class PDARunControl extends AbstractDsfService } public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor rm) { - PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Operation not implemented"); + IExecutionDMContext[] threads = new IExecutionDMContext[fThreads.size()]; + int i = 0; + for (ThreadInfo info : fThreads.values()) { + threads[i++] = info.fContext; + } + rm.setData(threads); + rm.done(); } - public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor rm){ - rm.setData( new ExecutionDMData(fStateChangeReason) ); + public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor rm) { + if (dmc instanceof PDAThreadDMContext) { + ThreadInfo info = fThreads.get(((PDAThreadDMContext)dmc).getID()); + if (info == null) { + PDAPlugin.failRequest(rm, INVALID_HANDLE, "Unknown DMC type"); + return; + } + rm.setData( new ExecutionDMData(info.fStateChangeReason) ); + } else { + rm.setData( new ExecutionDMData(fVMStateChangeReason) ); + } rm.done(); } } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStack.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStack.java index 90abe899d44..55d3371a801 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStack.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStack.java @@ -13,6 +13,8 @@ package org.eclipse.dd.examples.pda.service; import java.util.Hashtable; import org.eclipse.cdt.core.IAddress; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; import org.eclipse.dd.dsf.concurrent.Immutable; @@ -55,7 +57,7 @@ public class PDAStack extends AbstractDsfService implements IStack { final private int fLevel; - FrameDMContext(String sessionId, IExecutionDMContext execDmc, int level) { + FrameDMContext(String sessionId, PDAThreadDMContext execDmc, int level) { super(sessionId, new IDMContext[] { execDmc }); fLevel = level; } @@ -119,7 +121,7 @@ public class PDAStack extends AbstractDsfService implements IStack { final private String fVariable; - VariableDMContext(String sessionId, IFrameDMContext frameCtx, String variable) { + VariableDMContext(String sessionId, FrameDMContext frameCtx, String variable) { super(sessionId, new IDMContext[] { frameCtx }); fVariable = variable; } @@ -219,9 +221,18 @@ public class PDAStack extends AbstractDsfService implements IStack { } public void getFrameData(final IFrameDMContext frameCtx, final DataRequestMonitor rm) { + PDAThreadDMContext threadCtx = + DMContexts.getAncestorOfType(frameCtx, PDAThreadDMContext.class); + + if (threadCtx == null) { + rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + frameCtx, null)); + rm.done(); + return; + } + // Execute the PDA stack command, or retrieve the result from cache if already available. fCommandCache.execute( - new PDAStackCommand(fCommandControl.getProgramDMContext()), + new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -246,21 +257,24 @@ public class PDAStack extends AbstractDsfService implements IStack { // however the argument context is a generic context type, so it could // be an execution context, a frame, a variable, etc. Search the // hierarchy of the argument context to find the execution one. - final IExecutionDMContext execCtx = DMContexts.getAncestorOfType(context, IExecutionDMContext.class); - if (execCtx == null) { - PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + context); - return; + final PDAThreadDMContext threadCtx = + DMContexts.getAncestorOfType(context, PDAThreadDMContext.class); + + if (threadCtx == null) { + rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null)); + rm.done(); + return; } // Execute the stack command and create the corresponding frame contexts. fCommandCache.execute( - new PDAStackCommand(fCommandControl.getProgramDMContext()), + new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { IFrameDMContext[] frameCtxs = new IFrameDMContext[getData().fFrames.length]; for (int i = 0; i < getData().fFrames.length; i++) { - frameCtxs[i] = new FrameDMContext(getSession().getId(), execCtx, i); + frameCtxs[i] = new FrameDMContext(getSession().getId(), threadCtx, i); } rm.setData(frameCtxs); rm.done(); @@ -268,10 +282,25 @@ public class PDAStack extends AbstractDsfService implements IStack { }); } - public void getLocals(final IFrameDMContext frameCtx, final DataRequestMonitor rm) { - // Execute the stack command again. + public void getLocals(IFrameDMContext context, final DataRequestMonitor rm) { + if (!(context instanceof FrameDMContext)) { + rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null)); + rm.done(); + return; + } + final FrameDMContext frameCtx = (FrameDMContext)context; + + final PDAThreadDMContext threadCtx = + DMContexts.getAncestorOfType(frameCtx, PDAThreadDMContext.class); + + if (threadCtx == null) { + rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + frameCtx, null)); + rm.done(); + return; + } + fCommandCache.execute( - new PDAStackCommand(fCommandControl.getProgramDMContext()), + new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -296,9 +325,18 @@ public class PDAStack extends AbstractDsfService implements IStack { } public void getStackDepth(IDMContext context, int maxDepth, final DataRequestMonitor rm) { + final PDAThreadDMContext threadCtx = + DMContexts.getAncestorOfType(context, PDAThreadDMContext.class); + + if (threadCtx == null) { + rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null)); + rm.done(); + return; + } + // Execute stack command and return the data's size. fCommandCache.execute( - new PDAStackCommand(fCommandControl.getProgramDMContext()), + new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -313,7 +351,7 @@ public class PDAStack extends AbstractDsfService implements IStack { // however the argument context is a generic context type, so it could // be an execution context, a frame, a variable, etc. Search the // hierarchy of the argument context to find the execution one. - final IExecutionDMContext execCtx = DMContexts.getAncestorOfType(context, IExecutionDMContext.class); + final PDAThreadDMContext execCtx = DMContexts.getAncestorOfType(context, PDAThreadDMContext.class); if (execCtx == null) { PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + context); return; diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStartedEvent.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStartedEvent.java index 801c561f5bd..1a31a2340d4 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStartedEvent.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStartedEvent.java @@ -11,12 +11,16 @@ package org.eclipse.dd.examples.pda.service; import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent; /** * Event issued when the PDA debugger is started. */ -public class PDAStartedEvent extends AbstractDMEvent { - PDAStartedEvent(PDAProgramDMContext context) { +public class PDAStartedEvent extends AbstractDMEvent + implements IStartedDMEvent +{ + PDAStartedEvent(PDAVirtualMachineDMContext context) { super(context); } } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDATerminatedEvent.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDATerminatedEvent.java index 0117f90c155..c33bd04b501 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDATerminatedEvent.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDATerminatedEvent.java @@ -11,12 +11,16 @@ package org.eclipse.dd.examples.pda.service; import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExitedDMEvent; /** * Event issued when the PDA debugger exits. */ -public class PDATerminatedEvent extends AbstractDMEvent { - PDATerminatedEvent(PDAProgramDMContext context) { +public class PDATerminatedEvent extends AbstractDMEvent + implements IExitedDMEvent +{ + PDATerminatedEvent(PDAVirtualMachineDMContext context) { super(context); } } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAThreadDMContext.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAThreadDMContext.java new file mode 100644 index 00000000000..659d4698978 --- /dev/null +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAThreadDMContext.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.examples.pda.service; + +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; + +/** + * Context representing a PDA thread. + */ +public class PDAThreadDMContext extends AbstractDMContext + implements IExecutionDMContext +{ + final private Integer fID; + + public PDAThreadDMContext(String sessionId, PDAVirtualMachineDMContext vmCtx, int id) { + super(sessionId, new IDMContext[] { vmCtx }); + fID = id; + } + + public int getID() { + return fID; + } + + @Override + public String toString() { + return super.baseToString() + ".thread[" + fID + "]"; + } + + @Override + public int hashCode() { + return baseHashCode() + fID.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return baseEquals(obj) && ((PDAThreadDMContext)obj).fID.equals(fID); + } +} diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAProgramDMContext.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAVirtualMachineDMContext.java similarity index 82% rename from plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAProgramDMContext.java rename to plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAVirtualMachineDMContext.java index 1dd8208c372..5c333378470 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAProgramDMContext.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAVirtualMachineDMContext.java @@ -14,12 +14,12 @@ import org.eclipse.core.runtime.PlatformObject; import org.eclipse.dd.dsf.datamodel.AbstractDMContext; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; -import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.service.DsfSession; /** - * Top-level Data Model context for the PDA debugger representing the PDA - * program. + * Top-level Data Model context for the PDA debugger representing the while PDA + * virtual machine. *

      * The PDA debugger is a single-threaded application. Therefore this * top level context implements IExecutionDMContext directly, hence this @@ -32,20 +32,20 @@ import org.eclipse.dd.dsf.service.DsfSession; * service to install/remove breakpoints. *

      *

      - * Note: There should only be one instance of PDACommandControlDMContext created - * by each PDA command control, so its equals method defaults to using + * Note: There should only be one instance of PDAVirtualMachineDMContext + * created by each PDA command control, so its equals method defaults to using * instance comparison. *

      */ -public class PDAProgramDMContext extends PlatformObject - implements IExecutionDMContext, IBreakpointsTargetDMContext +public class PDAVirtualMachineDMContext extends PlatformObject + implements IContainerDMContext, IBreakpointsTargetDMContext { final static IDMContext[] EMPTY_PARENTS_ARRAY = new IDMContext[0]; final private String fSessionId; final private String fProgram; - public PDAProgramDMContext(String sessionId, String program) { + public PDAVirtualMachineDMContext(String sessionId, String program) { fSessionId = sessionId; fProgram = program; } @@ -64,7 +64,7 @@ public class PDAProgramDMContext extends PlatformObject @Override public String toString() { - return "PDA(" + getSessionId() + ")"; + return "pda[" + getSessionId() + "]"; } /** diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/AbstractPDACommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/AbstractPDACommand.java index c0d527af93e..79206e35717 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/AbstractPDACommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/AbstractPDACommand.java @@ -14,7 +14,7 @@ import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.debug.service.command.ICommand; import org.eclipse.dd.dsf.debug.service.command.ICommandResult; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Base class for PDA commands. The PDA commands consist of a text request and @@ -27,7 +27,7 @@ abstract public class AbstractPDACommand implements final private IDMContext fContext; final private String fRequest; - public AbstractPDACommand(PDAProgramDMContext context, String request) { + public AbstractPDACommand(PDAVirtualMachineDMContext context, String request) { fContext = context; fRequest = request; } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAClearBreakpointCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAClearBreakpointCommand.java index 35b9717e3f9..df0b96b85ea 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAClearBreakpointCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAClearBreakpointCommand.java @@ -11,7 +11,7 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Clears any breakpoint set on given line @@ -25,7 +25,7 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; @Immutable public class PDAClearBreakpointCommand extends AbstractPDACommand { - public PDAClearBreakpointCommand(PDAProgramDMContext context, int line) { + public PDAClearBreakpointCommand(PDAVirtualMachineDMContext context, int line) { super(context, "clear " + (line - 1)); } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADataCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADataCommand.java index 2fa76f1bed4..df271216ff3 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADataCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADataCommand.java @@ -11,21 +11,24 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Retrieves data stack information * *
      - *    C: data
      + *    C: data {thread_id}
        *    R: {value 1}|{value 2}|{value 3}|...|
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      */ @Immutable public class PDADataCommand extends AbstractPDACommand { - public PDADataCommand(PDAProgramDMContext context) { - super(context, "data"); + public PDADataCommand(PDAVirtualMachineDMContext context, int threadId) { + super(context, "data " + threadId); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADropFrameCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADropFrameCommand.java index d68c173dd52..128f7353e37 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADropFrameCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADropFrameCommand.java @@ -11,24 +11,33 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Returns from the current frame without executing the rest of instructions. * *
      - *    C: drop
      + * If VM running:
      + *    C: drop {thread_id}
        *    R: ok
      - *    E: resumed drop
      - *    E: suspended drop
      + *    E: resumed {thread_id} drop
      + *    E: suspended {thread_id} drop
      + *    
      + * If VM suspended:
      + *    C: drop {thread_id}
      + *    R: ok
      + *    E: vmresumed drop
      + *    E: vmsuspended {thread_id} drop
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      - */ @Immutable public class PDADropFrameCommand extends AbstractPDACommand { - public PDADropFrameCommand(PDAProgramDMContext context) { - super(context, "drop"); + public PDADropFrameCommand(PDAVirtualMachineDMContext context, int threadId) { + super(context, "drop " + threadId); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEvalCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEvalCommand.java index 10a4d707132..3b6af5d0133 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEvalCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEvalCommand.java @@ -11,17 +11,22 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Sets what events cause the execution to stop. * *
      - *    C: eval {instruction}%20{parameter}|{instruction}%20{parameter}|...
      + *    C: eval {thread_id} {instruction}%20{parameter}|{instruction}%20{parameter}|...
        *    R: ok
      - *    E: resume client
      + *    E: resumed {thread_id} client
        *    E: evalresult result
      - *    E: suspended eval
      + *    E: suspended {thread_id} eval
      + *    
      + * Errors:
      + *    error: invalid thread
      + *    error: cannot evaluate while vm is suspended
      + *    error: thread running        
        * 
      * * Where event_name could be unimpinstr or nosuchlabel. @@ -29,8 +34,8 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; @Immutable public class PDAEvalCommand extends AbstractPDACommand { - public PDAEvalCommand(PDAProgramDMContext context, String operation) { - super(context, "eval " + operation); + public PDAEvalCommand(PDAVirtualMachineDMContext context, int threadId, String operation) { + super(context, "eval " + threadId + " " + operation); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEventStopCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEventStopCommand.java index d247f829c4b..7537012be38 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEventStopCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEventStopCommand.java @@ -11,7 +11,7 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Sets what events cause the execution to stop. @@ -30,7 +30,7 @@ public class PDAEventStopCommand extends AbstractPDACommand { public enum Event { UNIMPINSTR, NOSUCHLABEL }; - public PDAEventStopCommand(PDAProgramDMContext context, Event event, boolean enable) { + public PDAEventStopCommand(PDAVirtualMachineDMContext context, Event event, boolean enable) { super(context, "eventstop " + (event == Event.UNIMPINSTR ? "unimpinstr " : "nosuchlabel ") + diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAExitCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAExitCommand.java index 7b7222b7b27..1736c7a4648 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAExitCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAExitCommand.java @@ -11,7 +11,7 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Instructs the debugger to exit. @@ -24,7 +24,7 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; @Immutable public class PDAExitCommand extends AbstractPDACommand { - public PDAExitCommand(PDAProgramDMContext context) { + public PDAExitCommand(PDAVirtualMachineDMContext context) { super(context, "exit"); } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPopDataCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPopDataCommand.java index de6649b785b..4b8b1ec92be 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPopDataCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPopDataCommand.java @@ -11,21 +11,24 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Pops the top value from the data stack * *
      - *    C: popdata
      + *    C: popdata {thread_id}
        *    R: ok
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      */ @Immutable public class PDAPopDataCommand extends AbstractPDACommand { - public PDAPopDataCommand(PDAProgramDMContext context) { - super(context, "popdata"); + public PDAPopDataCommand(PDAVirtualMachineDMContext context, int threadId) { + super(context, "popdata " + threadId); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPushDataCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPushDataCommand.java index d201e9b05ec..d4861428270 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPushDataCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPushDataCommand.java @@ -11,21 +11,24 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Pushes the given value on top of the data stack. * *
      - *    C: pushdata {value}
      + *    C: pushdata {thread_id} {value}
        *    R: ok
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      */ @Immutable public class PDAPushDataCommand extends AbstractPDACommand { - public PDAPushDataCommand(PDAProgramDMContext context, int value) { - super(context, "pushdata " + value); + public PDAPushDataCommand(PDAVirtualMachineDMContext context, int threadId, int value) { + super(context, "pushdata " + threadId + " " + value); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAResumeCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAResumeCommand.java index 6a7e46f1a29..b49879bd45f 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAResumeCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAResumeCommand.java @@ -11,22 +11,28 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** - * Resumes the execution + * Resumes the execution of a single thread. Can be issued only if the virtual + * machine is running. * *
      - *    C: resume
      + *    C: resume {thread_id}
        *    R: ok
      - *    E: resumed client
      + *    E: resumed {thread_id} client
      + *    
      + * Errors:
      + *    error: invalid thread
      + *    error: cannot resume thread when vm is suspended
      + *    error: thread already running
        * 
      */ @Immutable public class PDAResumeCommand extends AbstractPDACommand { - public PDAResumeCommand(PDAProgramDMContext context) { - super(context, "resume"); + public PDAResumeCommand(PDAVirtualMachineDMContext context, int threadId) { + super(context, "resume " + threadId); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetBreakpointCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetBreakpointCommand.java index 4bfd3370df6..c6cad586b14 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetBreakpointCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetBreakpointCommand.java @@ -11,24 +11,35 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Sets a breakpoint at given line * *
      - *    C: set {line_number}
      + * Suspend a single thread:
      + *    C: set {line_number} 0
        *    R: ok
      - *    C: resume
      - *    E: resumed client
      - *    E: suspended breakpoint line_number
      + *    C: resume {thread_id}
      + *    E: resumed {thread_id} client
      + *    E: suspended {thread_id} breakpoint line_number
      + *    
      + * Suspend the VM:
      + *    C: set {line_number} 1
      + *    R: ok
      + *    C: vmresume
      + *    E: vmresumed client
      + *    E: vmsuspended {thread_id} breakpoint line_number
        * 
      */ @Immutable public class PDASetBreakpointCommand extends AbstractPDACommand { - public PDASetBreakpointCommand(PDAProgramDMContext context, int line) { - super(context, "set " + (line - 1)); + public PDASetBreakpointCommand(PDAVirtualMachineDMContext context, int line, boolean stopVM) { + super(context, + "set " + + (line - 1) + " " + + (stopVM ? "1" : "0")); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetDataCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetDataCommand.java index 706700c8f7f..92972c47ef6 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetDataCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetDataCommand.java @@ -11,21 +11,24 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Sets a data value in the data stack at the given location * *
      - *    C: setdata {index} {value}
      + *    C: setdata {thread_id} {index} {value}
        *    R: ok
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      */ @Immutable public class PDASetDataCommand extends AbstractPDACommand { - public PDASetDataCommand(PDAProgramDMContext context, int index, String value) { - super(context, "setdata " + index + " " + value); + public PDASetDataCommand(PDAVirtualMachineDMContext context, int threadId, int index, String value) { + super(context, "setdata " + threadId + " " + index + " " + value); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetVarCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetVarCommand.java index f18340e20d4..5e058ecff83 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetVarCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetVarCommand.java @@ -11,21 +11,24 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Sets a variable value * *
      - *    C: setvar {frame_number} {variable} {value}
      + *    C: setvar {thread_id} {frame_number} {variable} {value}
        *    R: ok
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      */ @Immutable public class PDASetVarCommand extends AbstractPDACommand { - public PDASetVarCommand(PDAProgramDMContext context, int frame, String variable, String value) { - super(context, "setvar " + frame + " " + variable + " " + value); + public PDASetVarCommand(PDAVirtualMachineDMContext context, int threadId, int frame, String variable, String value) { + super(context, "setvar " + threadId + " " + frame + " " + variable + " " + value); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStackCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStackCommand.java index aef4d4aa795..c99f3c32073 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStackCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStackCommand.java @@ -11,21 +11,24 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Retrieves command stack information * *
      - *    C: stack
      + *    C: stack {thread_id}
        *    R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#...
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      */ @Immutable public class PDAStackCommand extends AbstractPDACommand { - public PDAStackCommand(PDAProgramDMContext context) { - super(context, "stack"); + public PDAStackCommand(PDAVirtualMachineDMContext context, int threadId) { + super(context, "stack " + threadId); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepCommand.java index ce50cf5c228..5401c8ec11e 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepCommand.java @@ -11,23 +11,33 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Executes next instruction * *
      - *    C: step
      + * If VM running:
      + *    C: step {thread_id}
        *    R: ok
      - *    E: resumed client
      - *    E: suspended step
      + *    E: resumed {thread_id} client
      + *    E: suspended {thread_id} step
      + *    
      + * If VM suspended:
      + *    C: step {thread_id}
      + *    R: ok
      + *    E: vmresumed client
      + *    E: vmsuspended {thread_id} step
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      */ @Immutable public class PDAStepCommand extends AbstractPDACommand { - public PDAStepCommand(PDAProgramDMContext context) { - super(context, "step"); + public PDAStepCommand(PDAVirtualMachineDMContext context, int threadId) { + super(context, "step " + threadId); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepReturnCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepReturnCommand.java index 8b9d7c8a675..7a588019360 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepReturnCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepReturnCommand.java @@ -11,23 +11,33 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Executes instructions until the current subroutine is finished * *
      - *    C: stepreturn
      + * If VM running:
      + *    C: stepreturn {thread_id}
        *    R: ok
      - *    E: resumed step
      - *    E: suspended step
      + *    E: resumed {thread_id} client
      + *    E: suspended {thread_id} step
      + *    
      + * If VM suspended:
      + *    C: stepreturn {thread_id}
      + *    R: ok
      + *    E: vmresumed client
      + *    E: vmsuspended {thread_id} step
      + *    
      + * Errors:
      + *    error: invalid thread
        * 
      */ @Immutable public class PDAStepReturnCommand extends AbstractPDACommand { - public PDAStepReturnCommand(PDAProgramDMContext context) { - super(context, "stepreturn"); + public PDAStepReturnCommand(PDAVirtualMachineDMContext context, int threadId) { + super(context, "stepreturn " + threadId); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASuspendCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASuspendCommand.java index 5abde431178..a3ad5bd86b3 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASuspendCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASuspendCommand.java @@ -11,22 +11,28 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** - * Suspends execution + * Suspends execution of a single thread. Can be issued only if the virtual + * machine is running. * *
      - *    C: suspend
      + *    C: suspend {thread_id}
        *    R: ok
      - *    E: suspended client
      + *    E: suspended {thread_id} client
      + *    
      + * Errors:
      + *    error: invalid thread
      +      error: vm already suspended
      + *    error: thread already suspended
        * 
      */ @Immutable public class PDASuspendCommand extends AbstractPDACommand { - public PDASuspendCommand(PDAProgramDMContext context) { - super(context, "suspend"); + public PDASuspendCommand(PDAVirtualMachineDMContext context, int threadId) { + super(context, "suspend " + threadId); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMResumeCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMResumeCommand.java new file mode 100644 index 00000000000..627ffdb9390 --- /dev/null +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMResumeCommand.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.examples.pda.service.commands; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; + +/** + * Resumes the execution of the whole virtual machine + * + *
      + *    C: vmresume
      + *    R: ok
      + *    E: vmresumed client
      + *    
      + * Errors:
      + *    error: vm already running
      + * 
      + */ +@Immutable +public class PDAVMResumeCommand extends AbstractPDACommand { + + public PDAVMResumeCommand(PDAVirtualMachineDMContext context) { + super(context, "vmresume"); + } + + @Override + public PDACommandResult createResult(String resultText) { + return new PDACommandResult(resultText); + } +} diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMSuspendCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMSuspendCommand.java new file mode 100644 index 00000000000..c406ba8b5b5 --- /dev/null +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMSuspendCommand.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.examples.pda.service.commands; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; + +/** + * Suspends the execution of the whole virtual machine + * + *
      + *    C: vmsuspend
      + *    R: ok
      + *    E: vmsuspended client
      + *    
      + * Errors:
      + *    error: thread already suspended
      + * 
      + */ +@Immutable +public class PDAVMSuspendCommand extends AbstractPDACommand { + + public PDAVMSuspendCommand(PDAVirtualMachineDMContext context) { + super(context, "vmsuspend"); + } + + @Override + public PDACommandResult createResult(String resultText) { + return new PDACommandResult(resultText); + } +} diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVarCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVarCommand.java index cc57a527161..060e807bcbd 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVarCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVarCommand.java @@ -11,21 +11,25 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Retrieves variable value * *
      - *    C: var {frame_number} {variable_name}
      + *    C: var  {thread_id} {frame_number} {variable_name}
        *    R: {variable_value}
      + *    
      + * Errors:
      + *    error: invalid thread
      + *    error: variable undefined
        * 
      */ @Immutable public class PDAVarCommand extends AbstractPDACommand { - public PDAVarCommand(PDAProgramDMContext context, int frameId, String name) { - super(context, "var " + frameId + " " + name); + public PDAVarCommand(PDAVirtualMachineDMContext context, int threadId, int frameId, String name) { + super(context, "var " + threadId + " " + frameId + " " + name); } @Override diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAWatchCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAWatchCommand.java index f6bf1982545..7b1bb1c0a22 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAWatchCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAWatchCommand.java @@ -11,7 +11,7 @@ package org.eclipse.dd.examples.pda.service.commands; import org.eclipse.dd.dsf.concurrent.Immutable; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; /** * Sets a watchpoint on a given variable @@ -19,9 +19,9 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; *
        *    C: watch {function}::{variable_name} {watch_operation}
        *    R: ok
      - *    C: resume
      - *    R: resume client
      - *    E: suspended watch {watch_operation} {function}::{variable_name}
      + *    C: vmresume
      + *    R: vmresumed client
      + *    E: vmsuspended {thread_id} watch {watch_operation} {function}::{variable_name}
        * 
      */ @Immutable @@ -42,7 +42,7 @@ public class PDAWatchCommand extends AbstractPDACommand { } } - public PDAWatchCommand(PDAProgramDMContext context, String function, String variable, WatchOperation operation) { + public PDAWatchCommand(PDAVirtualMachineDMContext context, String function, String variable, WatchOperation operation) { super(context, "watch " + function+ "::" + variable + " " + getWatchOperationCode(operation)); } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java index 5d1f330f0d1..15e03f1dbd1 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java @@ -82,7 +82,7 @@ public class BasicTests extends CommandControlTestsBase { } }); - final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getProgramDMContext(), "data"); + final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getVirtualMachineDMContext(), "data 1"); // Test sending the command and checking all listeners were called. Query sendCommandQuery = new Query() { diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java index b2b2fb60d6c..e50b142cb1f 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java @@ -105,7 +105,7 @@ public class CommandControlTestsBase { protected void sendCommand(String command, String expectedResult) throws Throwable { - final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getProgramDMContext(), command); + final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getVirtualMachineDMContext(), command); // Test sending the command and checking all listeners were called. Query sendCommandQuery = new Query() { diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/PDATestCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/PDATestCommand.java index 36ba23c3527..2e8c6aa1112 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/PDATestCommand.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/PDATestCommand.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.dd.tests.pda.service.command; -import org.eclipse.dd.examples.pda.service.PDAProgramDMContext; +import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext; import org.eclipse.dd.examples.pda.service.commands.AbstractPDACommand; import org.eclipse.dd.examples.pda.service.commands.PDACommandResult; @@ -18,7 +18,7 @@ import org.eclipse.dd.examples.pda.service.commands.PDACommandResult; * */ class PDATestCommand extends AbstractPDACommand { - PDATestCommand(PDAProgramDMContext context, String command) { + PDATestCommand(PDAVirtualMachineDMContext context, String command) { super(context, command); } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test1.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test1.java index 2225c20f1ef..4d8f7c62482 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test1.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test1.java @@ -30,7 +30,7 @@ public class Test1 extends CommandControlTestsBase { @Test public void testRun() throws Throwable { - sendCommand("resume"); + sendCommand("vmresume"); expectOutput("\"hello\""); expectOutput("\"barfoo\""); expectOutput("\"first\""); diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test2.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test2.java index 88dc69f1878..8be032a6603 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test2.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test2.java @@ -31,79 +31,161 @@ public class Test2 extends CommandControlTestsBase { @Test public void testCommonDebugCommands() throws Throwable { - expectEvent("started"); + expectEvent("started 1"); // test step - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); // test breakpoint - sendCommand("set 4"); - sendCommand("data", "6|"); - sendCommand("resume"); - expectEvent("resumed client"); - expectEvent("suspended breakpoint 4"); + sendCommand("set 4 1"); + sendCommand("data 1", "6|"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("vmsuspended 1 breakpoint 4"); // test data stack - sendCommand("data", "6|7|8|9|"); - sendCommand("popdata"); - sendCommand("data", "6|7|8|"); - sendCommand("pushdata 11"); - sendCommand("data", "6|7|8|11|"); - sendCommand("setdata 1 2"); - sendCommand("data", "6|2|8|11|"); + sendCommand("data 1", "6|7|8|9|"); + sendCommand("popdata 1"); + sendCommand("data 1", "6|7|8|"); + sendCommand("pushdata 1 11"); + sendCommand("data 1", "6|7|8|11|"); + sendCommand("setdata 1 1 2"); + sendCommand("data 1", "6|2|8|11|"); // test call stack - sendCommand("set 12"); - sendCommand("set 19"); - sendCommand("stepreturn"); - expectEvent("resumed client"); - expectEvent("suspended breakpoint 12"); + sendCommand("set 12 1"); + sendCommand("set 19 1"); + sendCommand("stepreturn 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 breakpoint 12"); sendCommand("clear 19"); - sendCommand("stack", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" ); - sendCommand("stepreturn"); - expectEvent("resumed client"); - expectEvent("suspended step"); - sendCommand("stack", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" ); - sendCommand("stepreturn"); - expectEvent("resumed client"); - expectEvent("suspended step"); - sendCommand("stack", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" ); - sendCommand("set 6"); - sendCommand("stepreturn"); - expectEvent("resumed client"); - expectEvent("suspended breakpoint 6"); + sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" ); + sendCommand("stepreturn 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" ); + sendCommand("stepreturn 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" ); + sendCommand("set 6 1"); + sendCommand("stepreturn 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 breakpoint 6"); // test set and clear - sendCommand("set 27"); - sendCommand("set 29"); - sendCommand("set 33"); - sendCommand("resume"); - expectEvent("resumed client"); - expectEvent("suspended breakpoint 33"); - sendCommand("resume"); - expectEvent("resumed client"); - expectEvent("suspended breakpoint 27"); + sendCommand("set 27 1"); + sendCommand("set 29 1"); + sendCommand("set 33 1"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("vmsuspended 1 breakpoint 33"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("vmsuspended 1 breakpoint 27"); sendCommand("clear 33"); - sendCommand("resume"); - expectEvent("resumed client"); - expectEvent("suspended breakpoint 29"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("vmsuspended 1 breakpoint 29"); // test var and setvar - sendCommand("set 47"); - sendCommand("resume"); - expectEvent("resumed client"); - expectEvent("suspended breakpoint 47"); - sendCommand("var 1 b", "4"); - sendCommand("var 2 b", "2"); - sendCommand("var 1 a", "0"); - sendCommand("setvar 1 a 99"); - sendCommand("data", "6|2|8|11|27|1|4|"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("var 1 a", "99"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("data", "6|2|8|11|27|1|4|99|"); + sendCommand("set 47 1"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("vmsuspended 1 breakpoint 47"); + sendCommand("var 1 1 b", "4"); + sendCommand("var 1 2 b", "2"); + sendCommand("var 1 1 a", "0"); + sendCommand("setvar 1 1 a 99"); + sendCommand("data 1", "6|2|8|11|27|1|4|"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("var 1 1 a", "99"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("data 1", "6|2|8|11|27|1|4|99|"); + sendCommand("var 1 1 x", "error: variable undefined"); + sendCommand("setvar 1 1 x 100"); + sendCommand("var 1 1 x", "100"); // test exit sendCommand("exit"); expectEvent("terminated"); } + + @Test + public void testCommonDebugCommandsWithThreadRC() throws Throwable { + expectEvent("started 1"); + // test breakpoint + sendCommand("set 3 0"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("suspended 1 breakpoint 3"); + sendCommand("data 1", "6|7|8|"); + // test step + sendCommand("step 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 step"); + // test data stack + sendCommand("data 1", "6|7|8|9|"); + sendCommand("popdata 1"); + sendCommand("data 1", "6|7|8|"); + sendCommand("pushdata 1 11"); + sendCommand("data 1", "6|7|8|11|"); + sendCommand("setdata 1 1 2"); + sendCommand("data 1", "6|2|8|11|"); + // test call stack + sendCommand("set 12 0"); + sendCommand("set 19 0"); + sendCommand("stepreturn 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 breakpoint 12"); + sendCommand("clear 19"); + sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" ); + sendCommand("stepreturn 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 step"); + sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" ); + sendCommand("stepreturn 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 step"); + sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" ); + sendCommand("set 6 0"); + sendCommand("stepreturn 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 breakpoint 6"); + // test set and clear + sendCommand("set 27 0"); + sendCommand("set 29 0"); + sendCommand("set 33 0"); + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("suspended 1 breakpoint 33"); + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("suspended 1 breakpoint 27"); + sendCommand("clear 33"); + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("suspended 1 breakpoint 29"); + // test var and setvar + sendCommand("set 47 0"); + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("suspended 1 breakpoint 47"); + sendCommand("var 1 1 b", "4"); + sendCommand("var 1 2 b", "2"); + sendCommand("var 1 1 a", "0"); + sendCommand("setvar 1 1 a 99"); + sendCommand("data 1", "6|2|8|11|27|1|4|"); + sendCommand("step 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 step"); + sendCommand("var 1 1 a", "99"); + sendCommand("step 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 step"); + sendCommand("data 1", "6|2|8|11|27|1|4|99|"); + // test exit + sendCommand("exit"); + expectEvent("terminated"); + } + } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test3.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test3.java index 2df4d2339b1..00ac9b6c24a 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test3.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test3.java @@ -31,43 +31,59 @@ public class Test3 extends CommandControlTestsBase { @Test public void testUncaughtEvents() throws Throwable { - expectEvent("started"); - sendCommand("resume"); - expectEvent("resumed client"); + expectEvent("started 1"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); expectEvent("unimplemented instruction foobar"); expectEvent("no such label zippy"); + expectEvent("no such label swishy"); + expectEvent("exited 1"); expectEvent("terminated"); } - + @Test public void testCaughtUnimpinstrEvents() throws Throwable { - expectEvent("started"); + expectEvent("started 1"); sendCommand("eventstop unimpinstr 1"); - sendCommand("resume"); - expectEvent("resumed client"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); expectEvent("unimplemented instruction foobar"); - expectEvent("suspended event unimpinstr"); + expectEvent("vmsuspended 1 event unimpinstr"); sendCommand("eventstop unimpinstr 0"); - sendCommand("resume"); - expectEvent("resumed client"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); expectEvent("unimplemented instruction foobar"); expectEvent("no such label zippy"); + expectEvent("no such label swishy"); + expectEvent("exited 1"); expectEvent("terminated"); } @Test public void testCaughtNosuchlabelEvents() throws Throwable { - expectEvent("started"); + expectEvent("started 1"); sendCommand("eventstop nosuchlabel 1"); - sendCommand("resume"); - expectEvent("resumed client"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); expectEvent("unimplemented instruction foobar"); expectEvent("no such label zippy"); - expectEvent("suspended event nosuchlabel"); + expectEvent("vmsuspended 1 event nosuchlabel"); sendCommand("eventstop nosuchlabel 0"); - sendCommand("resume"); - expectEvent("resumed client"); + sendCommand("set 11 1"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); expectEvent("no such label zippy"); + expectEvent("vmsuspended 1 breakpoint 11"); + sendCommand("eventstop nosuchlabel 1"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("no such label swishy"); + expectEvent("vmsuspended 1 event nosuchlabel"); + sendCommand("eventstop nosuchlabel 0"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("no such label swishy"); + expectEvent("exited 1"); expectEvent("terminated"); } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test6.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test6.java index 27543a9dc10..49a124de346 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test6.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test6.java @@ -31,49 +31,54 @@ public class Test6 extends CommandControlTestsBase { @Test public void testWatchPoints() throws Throwable { - expectEvent("started"); + expectEvent("started 1"); sendCommand("watch inner::a 1"); sendCommand("watch main::a 2"); - sendCommand("resume"); - expectEvent("resumed client"); - expectEvent("suspended watch write main::a"); - sendCommand("stack", fProgram + "|4|main|a|b"); - sendCommand("resume"); - expectEvent("resumed client"); - expectEvent("suspended watch read inner::a"); - sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|25|inner|a|c"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("vmsuspended 1 watch write main::a"); + sendCommand("stack 1", fProgram + "|4|main|a|b"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("vmsuspended 1 watch read inner::a"); + sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|25|inner|a|c"); sendCommand("watch inner::a 0"); - sendCommand("resume"); - expectEvent("resumed client"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("exited 1"); expectEvent("terminated"); } @Test public void testEval() throws Throwable { - expectEvent("started"); - sendCommand("set 25"); - sendCommand("resume"); - expectEvent("resumed client"); - expectEvent("suspended breakpoint 25"); + expectEvent("started 1"); - sendCommand("eval push%204|push%205|add"); - expectEvent("resumed client"); + sendCommand("eval 1 test_error", "error: cannot evaluate while vm is suspended"); + + sendCommand("set 25 0"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("suspended 1 breakpoint 25"); + + sendCommand("eval 1 push%204|push%205|add"); + expectEvent("resumed 1 eval"); expectEvent("evalresult 9"); - expectEvent("suspended eval"); + expectEvent("suspended 1 eval"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c"); - sendCommand("data", "4|4|"); - sendCommand("eval call%20other"); - expectEvent("resumed client"); + sendCommand("step 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 step"); + sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c"); + sendCommand("data 1", "4|4|"); + sendCommand("eval 1 call%20other"); + expectEvent("resumed 1 eval"); expectEvent("evalresult 15"); - expectEvent("suspended eval"); - sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c"); - sendCommand("data", "4|4|"); - sendCommand("resume"); - expectEvent("resumed client"); + expectEvent("suspended 1 eval"); + sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c"); + sendCommand("data 1", "4|4|"); + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("exited 1"); expectEvent("terminated"); } } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test8.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test8.java index 389f227d617..dc4a74a1004 100644 --- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test8.java +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test8.java @@ -31,40 +31,64 @@ public class Test8 extends CommandControlTestsBase { @Test public void testDropFrame() throws Throwable { - expectEvent("started"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c"); - sendCommand("drop"); - expectEvent("resumed drop"); - expectEvent("suspended drop"); - sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|7|inner|b"); - sendCommand("step"); - expectEvent("resumed step"); - expectEvent("suspended step"); - sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2"); - sendCommand("resume"); - expectEvent("resumed client"); + expectEvent("started 1"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c"); + sendCommand("drop 1"); + expectEvent("vmresumed drop"); + expectEvent("vmsuspended 1 drop"); + sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|7|inner|b"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("exited 1"); expectEvent("terminated"); } - + + @Test + public void testDropFrameWithThreadRC() throws Throwable { + expectEvent("started 1"); + sendCommand("set 12 0"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("suspended 1 breakpoint 12"); + sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c"); + sendCommand("drop 1"); + expectEvent("resumed 1 drop"); + expectEvent("suspended 1 drop"); + sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|7|inner|b"); + sendCommand("step 1"); + expectEvent("resumed 1 step"); + expectEvent("suspended 1 step"); + sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2"); + sendCommand("clear 12"); + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("exited 1"); + expectEvent("terminated"); + } + } diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test9.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test9.java new file mode 100644 index 00000000000..743b56d1987 --- /dev/null +++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test9.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.tests.pda.service.command; + +import java.io.File; + +import org.eclipse.core.runtime.Path; +import org.eclipse.dd.examples.pda.PDAPlugin; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * + */ +public class Test9 extends CommandControlTestsBase { + + @BeforeClass + public static void setProgram() { + File programFile = PDAPlugin.getFileInPlugin(new Path("pdavm/tests/vmtest9.pda")); + + fProgram = programFile.getPath(); + } + + @Test + public void testThreadsWithVMRC() throws Throwable { + expectEvent("started 1"); + sendCommand("state", "client"); + sendCommand("state 1", "vm"); + + // Check error responses + sendCommand("vmsuspend", "error: vm already suspended"); + sendCommand("resume 1", "error: cannot resume thread when vm is suspended"); + + // Run to thread create routine + sendCommand("threads", "1"); + sendCommand("set 2 1"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("vmsuspended 1 breakpoint 2"); + sendCommand("state", "1 breakpoint 2"); + sendCommand("state 1", "vm"); + + // Step over first thread create + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("started 2"); + expectEvent("vmsuspended 1 step"); + sendCommand("state", "1 step"); + sendCommand("state 1", "vm"); + sendCommand("threads", "1 2"); + sendCommand("stack 1", fProgram + "|3|main"); + sendCommand("stack 2", fProgram + "|9|foo"); + sendCommand("step 1"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 1 step"); + sendCommand("stack 1", fProgram + "|4|main"); + sendCommand("stack 2", fProgram + "|10|foo"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectOutput("thread_created"); + expectEvent("vmsuspended 1 breakpoint 2"); + + // Step over second thread create + sendCommand("step 2"); + expectEvent("vmresumed step"); + expectEvent("started 3"); + expectEvent("vmsuspended 2 step"); + sendCommand("threads", "1 2 3"); + sendCommand("stack 1", fProgram + "|3|main"); + sendCommand("stack 2", fProgram + "|13|foo#" + fProgram + "|15|inner"); + sendCommand("stack 3", fProgram + "|9|foo"); + sendCommand("step 3"); + expectEvent("vmresumed step"); + expectEvent("vmsuspended 3 step"); + sendCommand("stack 1", fProgram + "|4|main"); + sendCommand("stack 2", fProgram + "|13|foo#" + fProgram + "|16|inner|b"); + sendCommand("stack 3", fProgram + "|10|foo"); + + // Run to the end and watch threads starting/exiting. + sendCommand("clear 2"); + sendCommand("vmresume"); + expectOutput("thread_created"); + expectEvent("vmresumed client"); + expectEvent("started 4"); + expectEvent("exited 2"); + expectEvent("started 5"); + expectEvent("exited 3"); + expectEvent("started 6"); + expectEvent("exited 4"); + expectEvent("exited 1"); + expectEvent("exited 5"); + expectEvent("exited 6"); + expectEvent("terminated"); + } + + @Test + public void testThreadsWithThreadRC() throws Throwable { + expectEvent("started 1"); + + // Check error responses for thread run control + sendCommand("set 1 0"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("suspended 1 breakpoint 1"); + sendCommand("state", "running"); + sendCommand("state 1", "breakpoint 1"); + + sendCommand("resume", "error: invalid thread"); + sendCommand("vmresume", "error: vm already running"); + sendCommand("clear 1"); + sendCommand("suspend 1", "error: thread already suspended"); + sendCommand("vmsuspend"); + expectEvent("vmsuspended client"); + sendCommand("state", "client"); + sendCommand("state 1", "vm"); + sendCommand("suspend 1", "error: vm already suspended"); + sendCommand("resume 1", "error: cannot resume thread when vm is suspended"); + + // Create breakpoints at thread create and thread entry point. + sendCommand("set 2 0"); + sendCommand("set 10 0"); + sendCommand("vmresume"); + expectEvent("vmresumed client"); + expectEvent("suspended 1 breakpoint 2"); + + // Create first thread, and run it to completion + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("started 2"); + expectEvent("suspended 2 breakpoint 10"); + expectEvent("suspended 1 breakpoint 2"); + sendCommand("state 1", "breakpoint 2"); + sendCommand("state 2", "breakpoint 10"); + sendCommand("threads", "1 2"); + sendCommand("resume 2"); + expectEvent("resumed 2 client"); + expectEvent("exited 2"); + sendCommand("threads", "1"); + + // Create second thread, step it + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("started 3"); + expectEvent("suspended 3 breakpoint 10"); + expectEvent("suspended 1 breakpoint 2"); + sendCommand("threads", "1 3"); + sendCommand("stack 1", fProgram + "|2|main"); + sendCommand("stack 3", fProgram + "|10|foo"); + sendCommand("step 3"); + expectEvent("resumed 3 step"); + expectEvent("suspended 3 step"); + sendCommand("state 1", "breakpoint 2"); + sendCommand("state 3", "step"); + sendCommand("stack 1", fProgram + "|2|main"); + sendCommand("stack 3", fProgram + "|11|foo"); + + // Create the rest of threads + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("started 4"); + expectEvent("suspended 4 breakpoint 10"); + expectEvent("suspended 1 breakpoint 2"); + sendCommand("threads", "1 3 4"); + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + expectEvent("started 5"); + expectEvent("suspended 5 breakpoint 10"); + expectEvent("suspended 1 breakpoint 2"); + sendCommand("threads", "1 3 4 5"); + sendCommand("resume 1"); + expectEvent("resumed 1 client"); + + // Main thread exits + expectEvent("started 6"); + expectEvent("suspended 6 breakpoint 10"); + expectEvent("exited 1"); + sendCommand("threads", "3 4 5 6"); + + // Exit + sendCommand("exit"); + expectEvent("terminated"); + } + +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java index ab7947a8cd2..087f2515c77 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java @@ -68,38 +68,36 @@ public class ContainerVMNode extends AbstractContainerVMNode @Override - protected void updateLabelInSessionThread(ILabelUpdate[] updates) { - for (final ILabelUpdate update : updates) { - final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); - if ( runControl == null ) { - handleFailedUpdate(update); - continue; - } - - final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class); - - String imageKey = null; - if (runControl.isSuspended(dmc)) { - imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED; - } else { - imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING; - } - update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0); - - runControl.getProcessData( - dmc, - new ViewerDataRequestMonitor(getExecutor(), update) { - @Override - public void handleCompleted() { - if (!isSuccess()) { - update.done(); - return; - } - update.setLabel(getData().getName(), 0); - update.done(); - } - }); + protected void updateLabelInSessionThread(final ILabelUpdate update) { + final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + if ( runControl == null ) { + handleFailedUpdate(update); + return; } + + final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class); + + String imageKey = null; + if (runControl.isSuspended(dmc)) { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED; + } else { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING; + } + update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0); + + runControl.getProcessData( + dmc, + new ViewerDataRequestMonitor(getExecutor(), update) { + @Override + public void handleCompleted() { + if (!isSuccess()) { + update.done(); + return; + } + update.setLabel(getData().getName(), 0); + update.done(); + } + }); } @Override diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java index 5feeaef3506..a79760fdfb8 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java @@ -11,42 +11,21 @@ *******************************************************************************/ package org.eclipse.dd.gdb.internal.ui.viewmodel.launch; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import org.eclipse.dd.dsf.concurrent.DsfRunnable; -import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.concurrent.ThreadSafe; -import org.eclipse.dd.dsf.datamodel.DMContexts; -import org.eclipse.dd.dsf.datamodel.IDMContext; -import org.eclipse.dd.dsf.datamodel.IDMEvent; -import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.DelayedStackRefreshUpdatePolicy; -import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.FullStackRefreshEvent; +import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractLaunchVMProvider; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StackFramesVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StandardProcessVMNode; -import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent; -import org.eclipse.dd.dsf.debug.service.IRunControl; -import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; -import org.eclipse.dd.dsf.ui.viewmodel.IVMModelProxy; import org.eclipse.dd.dsf.ui.viewmodel.IVMNode; -import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; -import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.GDBExitedEvent; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.GDBStartedEvent; import org.eclipse.dd.mi.service.command.MIInferiorProcess.InferiorExitedDMEvent; import org.eclipse.dd.mi.service.command.MIInferiorProcess.InferiorStartedDMEvent; -import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; -import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchesListener2; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; @@ -55,16 +34,9 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont * */ @SuppressWarnings("restriction") -public class LaunchVMProvider extends AbstractDMVMProvider +public class LaunchVMProvider extends AbstractLaunchVMProvider implements IDebugEventSetListener, ILaunchesListener2 { - /** - * Delay (in milliseconds) before a full stack trace will be requested. - */ - private static final int FRAME_UPDATE_DELAY= 200; - - private final Map> fRefreshStackFramesFutures = new HashMap>(); - @ThreadSafe public LaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) { @@ -89,85 +61,6 @@ public class LaunchVMProvider extends AbstractDMVMProvider DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); } - @Override - protected IVMUpdatePolicy[] createUpdateModes() { - return new IVMUpdatePolicy[] { new DelayedStackRefreshUpdatePolicy() }; - } - - public void handleDebugEvents(final DebugEvent[] events) { - if (isDisposed()) return; - - // We're in session's executor thread. Re-dispach to VM Adapter - // executor thread and then call root layout node. - try { - getExecutor().execute(new Runnable() { - public void run() { - if (isDisposed()) return; - - for (final DebugEvent event : events) { - handleEvent(event); - } - }}); - } catch (RejectedExecutionException e) { - // Ignore. This exception could be thrown if the provider is being - // shut down. - } - } - - @Override - protected void handleEvent(IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) { - super.handleEvent(proxyStrategy, event, rm); - - if (event instanceof IRunControl.ISuspendedDMEvent) { - final IExecutionDMContext exeContext= ((IRunControl.ISuspendedDMEvent) event).getDMContext(); - ScheduledFuture refreshStackFramesFuture = getRefreshFuture(exeContext); - // trigger delayed full stack frame update - if (refreshStackFramesFuture != null) { - // cancel previously scheduled frame update - refreshStackFramesFuture.cancel(false); - } - - refreshStackFramesFuture = getSession().getExecutor().schedule( - new DsfRunnable() { - public void run() { - if (getSession().isActive()) { - getExecutor().execute(new Runnable() { - public void run() { - // trigger full stack frame update - ScheduledFuture future= fRefreshStackFramesFutures.get(exeContext); - if (future != null && !isDisposed()) { - fRefreshStackFramesFutures.remove(exeContext); - handleEvent(new FullStackRefreshEvent(exeContext)); - } - }}); - } - } - }, - FRAME_UPDATE_DELAY, TimeUnit.MILLISECONDS); - fRefreshStackFramesFutures.put(exeContext, refreshStackFramesFuture); - } else if (event instanceof IRunControl.IResumedDMEvent) { - IExecutionDMContext exeContext= ((IRunControl.IResumedDMEvent) event).getDMContext(); - ScheduledFuture refreshStackFramesFuture= fRefreshStackFramesFutures.get(exeContext); - if (refreshStackFramesFuture != null) { - // cancel previously scheduled frame update - refreshStackFramesFuture.cancel(false); - fRefreshStackFramesFutures.remove(exeContext); - } - } - } - - /** - * Returns the future for the given execution context or for any child of the - * given execution context. - */ - private ScheduledFuture getRefreshFuture(IExecutionDMContext execCtx) { - for (IExecutionDMContext refreshCtx : fRefreshStackFramesFutures.keySet()) { - if (refreshCtx.equals(execCtx) || DMContexts.isAncestorOf(refreshCtx, execCtx)) { - return fRefreshStackFramesFutures.remove(refreshCtx); - } - } - return null; - } @Override public void dispose() { @@ -176,42 +69,6 @@ public class LaunchVMProvider extends AbstractDMVMProvider super.dispose(); } - public void launchesAdded(ILaunch[] launches) { - handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED)); - } - - public void launchesRemoved(ILaunch[] launches) { - handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED)); - } - - public void launchesChanged(ILaunch[] launches) { - handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED)); - } - - public void launchesTerminated(ILaunch[] launches) { - handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED)); - } - - private void handleLaunchesEvent(final LaunchesEvent event) { - if (isDisposed()) return; - - // We're in session's executor thread. Re-dispach to VM Adapter - // executor thread and then call root layout node. - try { - getExecutor().execute(new Runnable() { - public void run() { - if (isDisposed()) return; - - IRootVMNode rootLayoutNode = getRootVMNode(); - if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) { - handleEvent(event); - } - }}); - } catch (RejectedExecutionException e) { - // Ignore. This exception could be thrown if the provider is being - // shut down. - } - } @Override protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { @@ -223,22 +80,7 @@ public class LaunchVMProvider extends AbstractDMVMProvider { return false; } - - - // To optimize view performance when stepping rapidly, skip events that came - // before the last suspended events. However, the debug view can get suspended - // events for different threads, so make sure to skip only the events if they - // were in the same hierarchy as the last suspended event. - if (newEvent instanceof ISuspendedDMEvent && eventToSkip instanceof IDMEvent) { - IDMContext newEventDmc = ((IDMEvent)newEvent).getDMContext(); - IDMContext eventToSkipDmc = ((IDMEvent)eventToSkip).getDMContext(); - - if (newEventDmc.equals(eventToSkipDmc) || DMContexts.isAncestorOf(eventToSkipDmc, newEventDmc)) { - return true; - } - } - - return false; + return super.canSkipHandlingEvent(newEvent, eventToSkip); } }