1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56:01 +02:00

[236765] - [pda] Add multi-threading capability to PDA

This commit is contained in:
Pawel Piech 2008-06-16 18:30:54 +00:00
parent e90dbc258a
commit ee9c51a046
55 changed files with 2905 additions and 1475 deletions

View file

@ -12,19 +12,21 @@ package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch;
import java.util.concurrent.RejectedExecutionException; 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.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.DMContexts; 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.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl; 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.IContainerDMContext;
import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerResumedDMEvent; 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.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.IExitedDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent; import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent;
import org.eclipse.dd.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent; import org.eclipse.dd.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent;
import org.eclipse.dd.dsf.service.DsfSession; 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.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; 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.AbstractDMVMProvider;
@ -40,14 +42,16 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
public abstract class AbstractContainerVMNode extends AbstractDMVMNode implements IElementLabelProvider { public abstract class AbstractContainerVMNode extends AbstractDMVMNode implements IElementLabelProvider {
public AbstractContainerVMNode(AbstractDMVMProvider provider, DsfSession session) { public AbstractContainerVMNode(AbstractDMVMProvider provider, DsfSession session) {
super(provider, session, IRunControl.IExecutionDMContext.class); super(provider, session, IRunControl.IContainerDMContext.class);
} }
public void update(final ILabelUpdate[] updates) { public void update(final ILabelUpdate[] updates) {
try { try {
getSession().getExecutor().execute(new DsfRunnable() { getSession().getExecutor().execute(new DsfRunnable() {
public void run() { public void run() {
updateLabelInSessionThread(updates); for (final ILabelUpdate update : updates) {
updateLabelInSessionThread(update);
}
}}); }});
} catch (RejectedExecutionException e) { } catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) { for (ILabelUpdate update : updates) {
@ -62,26 +66,36 @@ public abstract class AbstractContainerVMNode extends AbstractDMVMNode implement
* @param updates the pending label updates * @param updates the pending label updates
* @see {@link #update(ILabelUpdate[]) * @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<IVMContext[]> rm) {
super.getContextsForEvent(parentDelta, e, rm);
}
public int getDeltaFlags(Object e) { public int getDeltaFlags(Object e) {
if (e instanceof IContainerResumedDMEvent && IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP)
if (e instanceof IContainerResumedDMEvent) {
if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP)
{ {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
}
} else if (e instanceof IContainerSuspendedDMEvent) { } else if (e instanceof IContainerSuspendedDMEvent) {
// no change, update happens on FullStackRefreshEvent
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} else if (e instanceof FullStackRefreshEvent) { } else if (e instanceof FullStackRefreshEvent) {
if (dmc instanceof IContainerDMContext) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} else if (e instanceof ISteppingTimedOutEvent && }
((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) } else if (e instanceof ISteppingTimedOutEvent) {
if (dmc instanceof IContainerDMContext)
{ {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
}
} else if (e instanceof IExitedDMEvent) { } else if (e instanceof IExitedDMEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} else if (e instanceof IStartedDMEvent) { } else if (e instanceof IStartedDMEvent) {
if (((IStartedDMEvent) e).getDMContext() instanceof IContainerDMContext) { if (dmc instanceof IContainerDMContext) {
return IModelDelta.EXPAND | IModelDelta.SELECT; return IModelDelta.EXPAND | IModelDelta.SELECT;
} else { } else {
return IModelDelta.CONTENT; 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) { public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
if(e instanceof IContainerResumedDMEvent && IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP)
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); parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
}
} else if (e instanceof IContainerSuspendedDMEvent) { } 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) { } else if (e instanceof FullStackRefreshEvent) {
parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT); // Full-stack refresh event is generated following a suspended event
} else if (e instanceof ISteppingTimedOutEvent && // and a fixed delay. If the suspended event was generated for the
((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) // container refresh the whole container.
{ if (dmc instanceof IContainerDMContext) {
parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT); parentDelta.addNode(createVMContext(dmc), 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. } else if (e instanceof ISteppingTimedOutEvent) {
parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.STATE); // 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) { } else if (e instanceof IExitedDMEvent) {
IExecutionDMContext exeContext= ((IExitedDMEvent) e).getDMContext(); // An exited event could either be for a thread within a container
if (exeContext instanceof IContainerDMContext) { // 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); parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
} else { } else {
IContainerDMContext containerCtx = DMContexts.getAncestorOfType(exeContext, IContainerDMContext.class); IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class);
if (containerCtx != null) { if (containerCtx != null) {
parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT); parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT);
} }
} }
} else if (e instanceof IStartedDMEvent) { } else if (e instanceof IStartedDMEvent) {
IExecutionDMContext exeContext= ((IStartedDMEvent) e).getDMContext(); // A started event could either be for a thread within a container
if (exeContext instanceof IContainerDMContext) { // or for the container itself.
parentDelta.addNode(createVMContext(exeContext), IModelDelta.EXPAND | IModelDelta.SELECT); // 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 { } else {
IContainerDMContext containerCtx = DMContexts.getAncestorOfType(exeContext, IContainerDMContext.class); IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class);
if (containerCtx != null) { if (containerCtx != null) {
parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT); parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT);
} }

View file

@ -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<IExecutionDMContext,ScheduledFuture<?>> fRefreshStackFramesFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
@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;
}
}

View file

@ -21,6 +21,7 @@ import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.DMContexts; 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.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl; 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.IContainerDMContext;
@ -219,24 +220,19 @@ public abstract class AbstractThreadVMNode extends AbstractDMVMNode
public int getDeltaFlags(Object e) { public int getDeltaFlags(Object e) {
if (e instanceof IContainerResumedDMEvent || e instanceof IContainerSuspendedDMEvent) { IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
// No need to react to container events, because the container
// nodes will deal with them. We need this if statement however, if (dmc instanceof IContainerDMContext) {
// because the these events extend IResumedDMEvent and
// ISuspendedDMEvent and would trigger the if statement below.
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} else if (e instanceof IResumedDMEvent && } else if (e instanceof IResumedDMEvent &&
((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) ((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP)
{ {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} else if (e instanceof ISuspendedDMEvent) { } else if (e instanceof ISuspendedDMEvent) {
// no change, update happens on FullStackRefreshEvent
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} else if (e instanceof FullStackRefreshEvent) { } else if (e instanceof FullStackRefreshEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} else if (e instanceof ISteppingTimedOutEvent && } else if (e instanceof ISteppingTimedOutEvent) {
!(((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) )
{
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} else if (e instanceof ModelProxyInstalledEvent) { } else if (e instanceof ModelProxyInstalledEvent) {
return IModelDelta.SELECT | IModelDelta.EXPAND; 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) { public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
if(e instanceof IContainerResumedDMEvent || e instanceof IContainerSuspendedDMEvent) { IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
// No need to react to container events, because the container
// nodes will deal with them. We need this if statement however, if(dmc instanceof IContainerDMContext) {
// because the these events extend IResumedDMEvent and // The IContainerDMContext sub-classes IExecutionDMContext.
// ISuspendedDMEvent and would trigger the if statement below. // 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(); rm.done();
} else if(e instanceof IResumedDMEvent && } else if(e instanceof IResumedDMEvent) {
((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) // Resumed:
{ // - If not stepping, update the thread and its content (its stack).
parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT); // - 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(); rm.done();
}
} else if (e instanceof ISuspendedDMEvent) { } 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(); rm.done();
} else if (e instanceof FullStackRefreshEvent) { } 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(); rm.done();
} else if (e instanceof ISteppingTimedOutEvent && } else if (e instanceof ISteppingTimedOutEvent) {
!(((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) ) // Stepping time-out indicates that a step operation is taking
{ // a long time, and the view needs to be refreshed to show
parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT); // the user that the program is running.
// Workaround for bug 233730: we need to add a separate delta node for the state flag in parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
// order to trigger an update of the run control actions.
parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.STATE);
rm.done(); rm.done();
} else if (e instanceof ModelProxyInstalledEvent) { } 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( getThreadVMCForModelProxyInstallEvent(
parentDelta, parentDelta,
new DataRequestMonitor<VMContextInfo>(getExecutor(), rm) { new DataRequestMonitor<VMContextInfo>(getExecutor(), rm) {

View file

@ -22,7 +22,7 @@ import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.dd.examples.pda.service.PDACommandControl; 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.dd.examples.pda.ui.PDAUIPlugin;
import org.eclipse.debug.core.commands.IDebugCommandRequest; import org.eclipse.debug.core.commands.IDebugCommandRequest;
import org.eclipse.debug.core.commands.IEnabledStateRequest; 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, // Find the PDA program context in the selected element. If one is not found,
// the action should be disabled. // the action should be disabled.
IDMVMContext vmc = (IDMVMContext)request.getElements()[0]; 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) { if (pdaProgramCtx == null) {
request.setEnabled(false); request.setEnabled(false);
request.done(); request.done();

View file

@ -11,39 +11,35 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.dd.examples.pda.ui.viewmodel.launch; 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.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.LaunchRootVMNode;
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StackFramesVMNode; 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.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.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode; 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.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchesListener2; import org.eclipse.debug.core.ILaunchesListener2;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/** /**
* View Model provider for the Launch (AKA Debug) view. The PDA debugger is * View Model provider for the Launch (AKA Debug) view. The launch VM
* single-threaded, so there is no need for a debug target element to be visible * provider is configured with three nodes:
* in the debug view. Therefore the launch VM provider is configured with three nodes:
* <ul> * <ul>
* <li> LaunchRootVMNode - This is the root of the PDA view model.</li> * <li> LaunchRootVMNode - This is the root of the PDA view model.</li>
* <li> ThreadVMNode - Supplies the PDA program element.</li> * <li> PDAVirtualMachineVMNode - Supplies the element representing PDA VM</li>
* <li> PDAThreadsVMNode - Supplies the PDA thread elements</li>
* <li> StackFramesVMNode - Supplies the stack frame elements.</li> * <li> StackFramesVMNode - Supplies the stack frame elements.</li>
* <li> StandardProcessVMNode - Supplies elements representing the PDA debugger process.</li> * <li> StandardProcessVMNode - Supplies elements representing the PDA
* debugger process.</li>
* </ul> * </ul>
*/ */
@SuppressWarnings("restriction") @SuppressWarnings("restriction")
public class PDALaunchVMProvider extends AbstractDMVMProvider public class PDALaunchVMProvider extends AbstractLaunchVMProvider
implements IDebugEventSetListener, ILaunchesListener2 implements IDebugEventSetListener, ILaunchesListener2
{ {
@ThreadSafe @ThreadSafe
@ -55,82 +51,21 @@ public class PDALaunchVMProvider extends AbstractDMVMProvider
setRootNode(launchNode); setRootNode(launchNode);
// Launch node is a parent to the processes and program nodes. // 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); 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()); 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 // Register the LaunchVM provider as a listener to debug and launch
// events. These events are used by the launch and processes nodes. // events. These events are used by the launch and processes nodes.
DebugPlugin.getDefault().addDebugEventListener(this); DebugPlugin.getDefault().addDebugEventListener(this);
DebugPlugin.getDefault().getLaunchManager().addLaunchListener(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.
}
}
} }

View file

@ -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<IExecutionDMData>(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("<terminated> 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();
}
}
}

View file

@ -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<IExecutionDMData>(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();
}
}
}

View file

@ -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<IExecutionDMData>(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();
}
}
}

View file

@ -20,8 +20,11 @@ Clears any breakpoint set on given line
<h3>data</h3> <h3>data</h3>
Retrieves data stack information Retrieves data stack information
<pre> <pre>
C: data C: data {thread_id}
R: {value 1}|{value 2}|{value 3}|...| R: {value 1}|{value 2}|{value 3}|...|
Errors:
error: invalid thread
</pre> </pre>
@ -29,10 +32,20 @@ Retrieves data stack information
Returns from the current frame without executing the rest of instructions. Returns from the current frame without executing the rest of instructions.
<pre> <pre>
C: drop If VM running:
C: drop {thread_id}
R: ok R: ok
E: resumed drop E: resumed {thread_id} drop
E: suspended 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
</pre> </pre>
@ -40,11 +53,16 @@ Returns from the current frame without executing the rest of instructions.
Sets what events cause the execution to stop. Sets what events cause the execution to stop.
<pre> <pre>
C: eval {instruction}%20{parameter}|{instruction}%20{parameter}|... C: eval {thread_id} {instruction}%20{parameter}|{instruction}%20{parameter}|...
R: ok R: ok
E: resume client E: resumed {thread_id} client
E: evalresult result 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
</pre> </pre>
@ -72,8 +90,11 @@ Instructs the debugger to exit.
Pops the top value from the data stack Pops the top value from the data stack
<pre> <pre>
C: popdata C: popdata {thread_id}
R: ok R: ok
Errors:
error: invalid thread
</pre> </pre>
@ -81,18 +102,27 @@ Pops the top value from the data stack
Pushes the given value on top of the data stack. Pushes the given value on top of the data stack.
<pre> <pre>
C: pushdata {value} C: pushdata {thread_id} {value}
R: ok R: ok
Errors:
error: invalid thread
</pre> </pre>
<h3>resume</h3> <h3>resume</h3>
Resumes the execution Resumes the execution of a single thread. Can be issued only if the virtual
machine is running.
<pre> <pre>
C: resume C: resume {thread_id}
R: ok 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
</pre> </pre>
@ -100,11 +130,19 @@ Resumes the execution
Sets a breakpoint at given line Sets a breakpoint at given line
<pre> <pre>
C: set {line_number} Suspend a single thread:
C: set {line_number} 0
R: ok R: ok
C: resume C: resume {thread_id}
E: resumed client E: resumed {thread_id} client
E: suspended breakpoint line_number 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
</pre> </pre>
@ -112,8 +150,11 @@ Sets a breakpoint at given line
Sets a data value in the data stack at the given location Sets a data value in the data stack at the given location
<pre> <pre>
C: setdata {index} {value} C: setdata {thread_id} {index} {value}
R: ok R: ok
Errors:
error: invalid thread
</pre> </pre>
@ -121,8 +162,11 @@ Sets a data value in the data stack at the given location
Sets a variable value Sets a variable value
<pre> <pre>
C: setvar {frame_number} {variable} {value} C: setvar {thread_id} {frame_number} {variable} {value}
R: ok R: ok
Errors:
error: invalid thread
</pre> </pre>
@ -130,8 +174,11 @@ Sets a variable value
Retrieves command stack information Retrieves command stack information
<pre> <pre>
C: stack C: stack {thread_id}
R: {file}|{line}|{function}|{var_1}|{var_2}|...{file}|{line}|{function}|{var_1}|{var_2}|...... R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#...
Errors:
error: invalid thread
</pre> </pre>
@ -139,10 +186,20 @@ Retrieves command stack information
Executes next instruction Executes next instruction
<pre> <pre>
C: step If VM running:
C: step {thread_id}
R: ok R: ok
E: resumed step E: resumed {thread_id} client
E: suspended step 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
</pre> </pre>
@ -150,29 +207,56 @@ Executes next instruction
Executes instructions until the current subroutine is finished Executes instructions until the current subroutine is finished
<pre> <pre>
C: stepreturn If VM running:
C: stepreturn {thread_id}
R: ok R: ok
E: resumed step E: resumed {thread_id} client
E: suspended step 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
</pre> </pre>
<h3>suspend</h3> <h3>suspend</h3>
Suspends execution Suspends execution of a single thread. Can be issued only if the virtual
machine is running.
<pre> <pre>
C: suspend C: suspend {thread_id}
R: ok R: ok
E: suspended client E: suspended {thread_id} client
Errors:
error: invalid thread
error: vm already suspended
error: thread already suspended
</pre> </pre>
<h3>threads</h3>
Retrieves the list of active threads
<pre>
C: threads
R: {thread id} {thread id} ...
</pre>
<h3>var</h3> <h3>var</h3>
Retrieves variable value Retrieves variable value
<pre> <pre>
C: var {frame_number} {variable_name} C: var {thread_id} {frame_number} {variable_name}
R: {variable_value} R: {variable_value}
Errors:
error: invalid thread
error: variable undefined
</pre> </pre>
@ -194,5 +278,31 @@ The <code>watch_operation<code> value can be:
<li>2 - write watch</li> <li>2 - write watch</li>
<li>3 - both, etc.</li> <li>3 - both, etc.</li>
</ul> </ul>
<h3>vmresume</h3>
Resumes the execution of the whole virtual machine
<pre>
C: vmresume
R: ok
E: vmresumed client
Errors:
error: vm already running
</pre>
<h3>vmsuspend</h3>
Suspends the execution of the whole virtual machine
<pre>
C: vmsuspend
R: ok
E: vmsuspended client
Errors:
error: thread already suspended
</pre>
</body> </body>
</html> </html>

View file

@ -8,4 +8,6 @@ add
call zippy call zippy
add add
output output
push 1
branch_not_zero swishy
halt halt

View file

@ -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

View file

@ -78,7 +78,7 @@ public class PDAServicesInitSequence extends Sequence {
bpmService.initialize(new RequestMonitor(getExecutor(), requestMonitor) { bpmService.initialize(new RequestMonitor(getExecutor(), requestMonitor) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
bpmService.startTrackingBreakpoints(fCommandControl.getProgramDMContext(), requestMonitor); bpmService.startTrackingBreakpoints(fCommandControl.getVirtualMachineDMContext(), requestMonitor);
} }
}); });
} }
@ -107,7 +107,7 @@ public class PDAServicesInitSequence extends Sequence {
new Step() { new Step() {
@Override @Override
public void execute(RequestMonitor requestMonitor) { public void execute(RequestMonitor requestMonitor) {
fRunControl.resume(fCommandControl.getProgramDMContext(), requestMonitor); fRunControl.resume(fCommandControl.getVirtualMachineDMContext(), requestMonitor);
} }
}, },
}; };

View file

@ -51,7 +51,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
final Integer fLine; final Integer fLine;
public BreakpointDMContext(String sessionId, PDAProgramDMContext commandControlCtx, Integer line) { public BreakpointDMContext(String sessionId, PDAVirtualMachineDMContext commandControlCtx, Integer line) {
super(sessionId, new IDMContext[] { commandControlCtx }); super(sessionId, new IDMContext[] { commandControlCtx });
fLine = line; fLine = line;
} }
@ -81,7 +81,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
final String fFunction; final String fFunction;
final String fVariable; final String fVariable;
public WatchpointDMContext(String sessionId, PDAProgramDMContext commandControlCtx, String function, public WatchpointDMContext(String sessionId, PDAVirtualMachineDMContext commandControlCtx, String function,
String variable) String variable)
{ {
super(sessionId, new IDMContext[] { commandControlCtx }); super(sessionId, new IDMContext[] { commandControlCtx });
@ -164,7 +164,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
public void getBreakpoints(final IBreakpointsTargetDMContext context, final DataRequestMonitor<IBreakpointDMContext[]> rm) { public void getBreakpoints(final IBreakpointsTargetDMContext context, final DataRequestMonitor<IBreakpointDMContext[]> rm) {
// Validate the context // Validate the context
if (!fCommandControl.getProgramDMContext().equals(context)) { if (!fCommandControl.getVirtualMachineDMContext().equals(context)) {
PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoints target context"); PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoints target context");
return; return;
} }
@ -193,7 +193,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
// breakpoints mediator, which was called with the program context // breakpoints mediator, which was called with the program context
// in the services initialization sequence. So checking if // in the services initialization sequence. So checking if
// programCtx != null is mostly a formality. // programCtx != null is mostly a formality.
PDAProgramDMContext programCtx = DMContexts.getAncestorOfType(context, PDAProgramDMContext.class); PDAVirtualMachineDMContext programCtx = DMContexts.getAncestorOfType(context, PDAVirtualMachineDMContext.class);
if (programCtx != null) { if (programCtx != null) {
doInsertBreakpoint(programCtx, attributes, rm); doInsertBreakpoint(programCtx, attributes, rm);
} else { } else {
@ -209,7 +209,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
} }
} }
private void doInsertBreakpoint(PDAProgramDMContext programCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm) private void doInsertBreakpoint(PDAVirtualMachineDMContext programCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm)
{ {
// Compare the program path in the breakpoint with the path in the PDA // Compare the program path in the breakpoint with the path in the PDA
// program context. Only insert the breakpoint if the program matches. // 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 // installed already. PDA can only track a single breakpoint at a
// given line, attempting to set the second breakpoint should fail. // given line, attempting to set the second breakpoint should fail.
final BreakpointDMContext breakpointCtx = final BreakpointDMContext breakpointCtx =
new BreakpointDMContext(getSession().getId(), fCommandControl.getProgramDMContext(), line); new BreakpointDMContext(getSession().getId(), fCommandControl.getVirtualMachineDMContext(), line);
if (fBreakpoints.contains(breakpointCtx)) { if (fBreakpoints.contains(breakpointCtx)) {
PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already set"); PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already set");
return; return;
@ -244,7 +244,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
// still being processed here. // still being processed here.
fBreakpoints.add(breakpointCtx); fBreakpoints.add(breakpointCtx);
fCommandControl.queueCommand( fCommandControl.queueCommand(
new PDASetBreakpointCommand(fCommandControl.getProgramDMContext(), line), new PDASetBreakpointCommand(fCommandControl.getVirtualMachineDMContext(), line, false),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { 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 // installed already. PDA can only track a single watchpoint for a given
// function::variable, attempting to set the second breakpoint should fail. // function::variable, attempting to set the second breakpoint should fail.
final WatchpointDMContext watchpointCtx = final WatchpointDMContext watchpointCtx =
new WatchpointDMContext(getSession().getId(), fCommandControl.getProgramDMContext(), function, variable); new WatchpointDMContext(getSession().getId(), fCommandControl.getVirtualMachineDMContext(), function, variable);
if (fBreakpoints.contains(watchpointCtx)) { if (fBreakpoints.contains(watchpointCtx)) {
PDAPlugin.failRequest(rm, REQUEST_FAILED, "Watchpoint already set"); PDAPlugin.failRequest(rm, REQUEST_FAILED, "Watchpoint already set");
return; return;
@ -310,7 +310,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
// still being processed here. // still being processed here.
fBreakpoints.add(watchpointCtx); fBreakpoints.add(watchpointCtx);
fCommandControl.queueCommand( fCommandControl.queueCommand(
new PDAWatchCommand(fCommandControl.getProgramDMContext(), function, variable, watchOperation), new PDAWatchCommand(fCommandControl.getVirtualMachineDMContext(), function, variable, watchOperation),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
@ -350,7 +350,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
fBreakpoints.remove(bpCtx); fBreakpoints.remove(bpCtx);
fCommandControl.queueCommand( fCommandControl.queueCommand(
new PDAClearBreakpointCommand(fCommandControl.getProgramDMContext(), bpCtx.fLine), new PDAClearBreakpointCommand(fCommandControl.getVirtualMachineDMContext(), bpCtx.fLine),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm)); new DataRequestMonitor<PDACommandResult>(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 // Watchpoints are cleared using the same command, but with a "no watch" operation
fCommandControl.queueCommand( fCommandControl.queueCommand(
new PDAWatchCommand( new PDAWatchCommand(
fCommandControl.getProgramDMContext(), bpCtx.fFunction, bpCtx.fVariable, PDAWatchCommand.WatchOperation.NONE), fCommandControl.getVirtualMachineDMContext(), bpCtx.fFunction, bpCtx.fVariable, PDAWatchCommand.WatchOperation.NONE),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm)); new DataRequestMonitor<PDACommandResult>(getExecutor(), rm));
} }

View file

@ -89,7 +89,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
private boolean fTerminated = false; private boolean fTerminated = false;
// Data Model context of this command control. // Data Model context of this command control.
private PDAProgramDMContext fDMContext; private PDAVirtualMachineDMContext fDMContext;
// Synchronous listeners for commands and events. // Synchronous listeners for commands and events.
private final List<ICommandListener> fCommandListeners = new ArrayList<ICommandListener>(); private final List<ICommandListener> fCommandListeners = new ArrayList<ICommandListener>();
@ -137,12 +137,12 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
private void doInitialize(final RequestMonitor rm) { private void doInitialize(final RequestMonitor rm) {
// Create the control's data model context. // 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. // Add a listener for PDA events to track the started/terminated state.
addEventListener(new IEventListener() { addEventListener(new IEventListener() {
public void eventReceived(Object output) { public void eventReceived(Object output) {
if ("started".equals(output)) { if ("started 1".equals(output)) {
setStarted(); setStarted();
} else if ("terminated".equals(output)) { } else if ("terminated".equals(output)) {
setTerminated(); setTerminated();
@ -483,10 +483,10 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
/** /**
* Return the PDA Debugger top-level Data Model context. * Return the PDA Debugger top-level Data Model context.
* @see PDAProgramDMContext * @see PDAVirtualMachineDMContext
*/ */
@ThreadSafe @ThreadSafe
public PDAProgramDMContext getProgramDMContext() { public PDAVirtualMachineDMContext getVirtualMachineDMContext() {
return fDMContext; return fDMContext;
} }
@ -498,7 +498,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
processQueues(); processQueues();
// Issue a data model event. // 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(); processQueues();
// Issue a data model event. // Issue a data model event.
getSession().dispatchEvent(new PDATerminatedEvent(getProgramDMContext()), getProperties()); getSession().dispatchEvent(new PDATerminatedEvent(getVirtualMachineDMContext()), getProperties());
} }
} }

View file

@ -214,11 +214,12 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions {
// Create an expression based on the given context and string expression. // Create an expression based on the given context and string expression.
// The PDA debugger can only evaluate variables as expressions and only // The PDA debugger can only evaluate variables as expressions and only
// in context of a frame. // in context of a frame.
PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(ctx, PDAThreadDMContext.class);
IFrameDMContext frameCtx = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class); IFrameDMContext frameCtx = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class);
if (frameCtx != null) { if (threadCtx != null && frameCtx != null) {
return new ExpressionDMContext(getSession().getId(), frameCtx, expression); return new ExpressionDMContext(getSession().getId(), frameCtx, expression);
} else { } 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. // expression context, because a null return value is not allowed.
// Evaluating an invalid expression context will always yield an // Evaluating an invalid expression context will always yield an
// error. // error.
@ -276,6 +277,7 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions {
{ {
final ExpressionDMContext exprCtx = DMContexts.getAncestorOfType(formattedCtx, ExpressionDMContext.class); final ExpressionDMContext exprCtx = DMContexts.getAncestorOfType(formattedCtx, ExpressionDMContext.class);
if (exprCtx != null) { if (exprCtx != null) {
final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class);
final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class); final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);
// First retrieve the stack depth, needed to properly calculate // 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. // Send the command to evaluate the variable.
fCommandCache.execute( fCommandCache.execute(
new PDAVarCommand(fCommandControl.getProgramDMContext(), frameId, exprCtx.getExpression()), new PDAVarCommand(
fCommandControl.getVirtualMachineDMContext(),
threadCtx.getID(),
frameId,
exprCtx.getExpression()),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
@ -310,6 +316,7 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions {
final RequestMonitor rm) final RequestMonitor rm)
{ {
if (exprCtx instanceof ExpressionDMContext) { if (exprCtx instanceof ExpressionDMContext) {
final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class);
final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class); final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);
// Similarly to retrieving the variable, retrieve the // 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 // Send the "write" command to PDA debugger
fCommandCache.execute( fCommandCache.execute(
new PDASetVarCommand(fCommandControl.getProgramDMContext(), frameId, exprCtx.getExpression(), exprValue), new PDASetVarCommand(
fCommandControl.getVirtualMachineDMContext(),
threadCtx.getID(),
frameId,
exprCtx.getExpression(),
exprValue),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {

View file

@ -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) * @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<IRegisterGroupDMContext[]> rm ) { public void getRegisterGroups(IDMContext ctx, DataRequestMonitor<IRegisterGroupDMContext[]> rm ) {
PDAProgramDMContext execDmc = DMContexts.getAncestorOfType(ctx, PDAProgramDMContext.class); PDAVirtualMachineDMContext execDmc = DMContexts.getAncestorOfType(ctx, PDAVirtualMachineDMContext.class);
if (execDmc == null) { if (execDmc == null) {
rm.setStatus( new Status( IStatus.ERROR , PDAPlugin.PLUGIN_ID , INVALID_HANDLE , "Container context not found", null ) ) ; //$NON-NLS-1$ rm.setStatus( new Status( IStatus.ERROR , PDAPlugin.PLUGIN_ID , INVALID_HANDLE , "Container context not found", null ) ) ; //$NON-NLS-1$
rm.done(); rm.done();
@ -738,7 +738,7 @@ public class PDARegisters extends AbstractDsfService implements IRegisters {
private int fGroupNo; private int fGroupNo;
private String fGroupName; 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 }); super(service.getSession().getId(), new IDMContext[] { execDmc });
fGroupNo = groupNo; fGroupNo = groupNo;
fGroupName = groupName; fGroupName = groupName;

View file

@ -11,7 +11,11 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.dd.examples.pda.service; package org.eclipse.dd.examples.pda.service;
import java.util.Arrays;
import java.util.Hashtable; 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.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; 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.DsfServiceEventHandler;
import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.examples.pda.PDAPlugin; 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.PDACommandResult;
import org.eclipse.dd.examples.pda.service.commands.PDAResumeCommand; 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.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; import org.osgi.framework.BundleContext;
@ -56,6 +63,111 @@ public class PDARunControl extends AbstractDsfService
// events and track service state, to be perfectly in sync with the service // events and track service state, to be perfectly in sync with the service
// state. // state.
static final private IExecutionDMContext[] EMPTY_TRIGGERING_CONTEXTS_ARRAY = new IExecutionDMContext[0];
@Immutable
private static class ThreadResumedEvent extends AbstractDMEvent<IExecutionDMContext>
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<IExecutionDMContext>
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<IExecutionDMContext>
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<IExecutionDMContext>
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 @Immutable
private static class ExecutionDMData implements IExecutionDMData { private static class ExecutionDMData implements IExecutionDMData {
private final StateChangeReason fReason; private final StateChangeReason fReason;
@ -65,62 +177,63 @@ public class PDARunControl extends AbstractDsfService
public StateChangeReason getStateChangeReason() { return fReason; } public StateChangeReason getStateChangeReason() { return fReason; }
} }
@Immutable private static class ThreadStartedEvent extends AbstractDMEvent<IExecutionDMContext>
private static class ResumedEvent extends AbstractDMEvent<IExecutionDMContext> implements IStartedDMEvent
implements IResumedDMEvent
{ {
private final String fPDAEvent; ThreadStartedEvent(PDAThreadDMContext threadCtx) {
super(threadCtx);
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;
}
} }
} }
@Immutable private static class ThreadExitedEvent extends AbstractDMEvent<IExecutionDMContext>
private static class SuspendedEvent extends AbstractDMEvent<IExecutionDMContext> implements IExitedDMEvent
implements ISuspendedDMEvent
{ {
private final String fPDAEvent; ThreadExitedEvent(PDAThreadDMContext threadCtx) {
super(threadCtx);
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;
}
} }
} }
// Services // Services
private PDACommandControl fCommandControl; private PDACommandControl fCommandControl;
// State flags // Reference to the virtual machine data model context
private boolean fSuspended = true; private PDAVirtualMachineDMContext fDMContext;
private boolean fResumePending = false;
private boolean fStepping = false; // VM state flags
private StateChangeReason fStateChangeReason; 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<Integer, ThreadInfo> fThreads = new LinkedHashMap<Integer, ThreadInfo>();
public PDARunControl(DsfSession session) { public PDARunControl(DsfSession session) {
super(session); super(session);
@ -142,14 +255,21 @@ public class PDARunControl extends AbstractDsfService
} }
private void doInitialize(final RequestMonitor rm) { private void doInitialize(final RequestMonitor rm) {
// Cache a reference to the command control and the virtual machine context
fCommandControl = getServicesTracker().getService(PDACommandControl.class); fCommandControl = getServicesTracker().getService(PDACommandControl.class);
fDMContext = fCommandControl.getVirtualMachineDMContext();
// Add ourselves as a listener to PDA events, to catch suspended/resumed // Create the main thread context.
// events. 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); fCommandControl.addEventListener(this);
// Add ourselves as a listener to service events, in order to process // Add the run control service as a listener to service events as well,
// our own suspended/resumed events. // in order to process our own suspended/resumed/started/exited events.
getSession().addServiceEventListener(this, null); getSession().addServiceEventListener(this, null);
// Register the service with OSGi // Register the service with OSGi
@ -182,42 +302,137 @@ public class PDARunControl extends AbstractDsfService
if (!(output instanceof String)) return; if (!(output instanceof String)) return;
String event = (String)output; 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 // Handle PDA debugger suspended/resumed events and issue the
// corresponding Data Model events. Do not update the state // corresponding Data Model events. Do not update the state
// information until we start dispatching the service events. // information until we start dispatching the service events.
if (event.startsWith("suspended")) { IDMEvent<?> dmEvent = null;
IDMEvent<?> dmEvent = new SuspendedEvent(fCommandControl.getProgramDMContext(), event); if (eventName.equals("suspended") && thread != null) {
getSession().dispatchEvent(dmEvent, getProperties()); dmEvent = new ThreadSuspendedEvent(thread, reason);
} else if (event.startsWith("resumed")) { } else if (eventName.equals("resumed") && thread != null) {
IDMEvent<?> dmEvent = new ResumedEvent(fCommandControl.getProgramDMContext(), event); 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()); 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(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 @DsfServiceEventHandler
public void eventDispatched(ResumedEvent e) { public void eventDispatched(VMResumedEvent e) {
// This service should be the first to receive the ResumedEvent, fVMSuspended = false;
// (before any other listeners are called). Here, update the fVMResumePending = false;
// service state information based on the the resumed event. fVMStateChangeReason = e.getReason();
fSuspended = false; fVMStepping = e.getReason().equals(StateChangeReason.STEP);
fResumePending = false; for (ThreadInfo info : fThreads.values()) {
fStateChangeReason = e.getReason(); info.fSuspended = false;
fStepping = e.getReason().equals(StateChangeReason.STEP); 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 @DsfServiceEventHandler
public void eventDispatched(SuspendedEvent e) { public void eventDispatched(VMSuspendedEvent e) {
// This service should be the first to receive the SuspendedEvent also, fVMStateChangeReason = e.getReason();
// (before any other listeners are called). Here, update the fVMSuspendPending = false;
// service state information based on the the suspended event. fVMSuspended = true;
fStateChangeReason = e.getReason(); fVMStepping = false;
fResumePending = false; List<IExecutionDMContext> triggeringContexts = Arrays.asList(e.getTriggeringContexts());
fSuspended = true; for (ThreadInfo info : fThreads.values()) {
fStepping = false; 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<Boolean> rm) { public void canResume(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
rm.setData(doCanResume(context)); rm.setData(doCanResume(context));
@ -225,7 +440,34 @@ public class PDARunControl extends AbstractDsfService
} }
private boolean doCanResume(IExecutionDMContext context) { 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<Boolean> rm) { public void canSuspend(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
@ -234,34 +476,85 @@ public class PDARunControl extends AbstractDsfService
} }
private boolean doCanSuspend(IExecutionDMContext context) { 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) { 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) { 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) { public void resume(IExecutionDMContext context, final RequestMonitor rm) {
assert context != null; assert context != null;
if (doCanResume(context)) { if (doCanResume(context)) {
fResumePending = true; if (context instanceof PDAThreadDMContext) {
final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
fThreads.get(threadCtx.getID()).fResumePending = true;
fCommandControl.queueCommand( fCommandControl.queueCommand(
new PDAResumeCommand(fCommandControl.getProgramDMContext()), new PDAResumeCommand(fDMContext, threadCtx.getID()),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleFailure() { protected void handleFailure() {
// If the resume command failed, we no longer ThreadInfo threadState = fThreads.get(threadCtx.getID());
// expect to receive a resumed event. if (threadState != null) {
fResumePending = false; threadState.fResumePending = false;
}
super.handleFailure(); super.handleFailure();
} }
} }
); );
} else {
fVMResumePending = true;
fCommandControl.queueCommand(
new PDAVMResumeCommand(fDMContext),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
@Override
protected void handleFailure() {
fVMResumePending = false;
super.handleFailure();
}
}
);
}
} else { } else {
PDAPlugin.failRequest(rm, INVALID_STATE, "Given context: " + context + ", is already running."); PDAPlugin.failRequest(rm, INVALID_STATE, "Given context: " + context + ", is already running.");
} }
@ -271,35 +564,79 @@ public class PDARunControl extends AbstractDsfService
assert context != null; assert context != null;
if (doCanSuspend(context)) { if (doCanSuspend(context)) {
if (context instanceof PDAThreadDMContext) {
final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
fThreads.get(threadCtx.getID()).fSuspendPending = true;
fCommandControl.queueCommand( fCommandControl.queueCommand(
new PDASuspendCommand(fCommandControl.getProgramDMContext()), new PDAVMSuspendCommand(fDMContext),
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm)); new DataRequestMonitor<PDACommandResult>(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<PDACommandResult>(getExecutor(), rm) {
@Override
protected void handleFailure() {
fVMSuspendPending = false;
super.handleFailure();
}
}
);
}
} else { } else {
PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_STATE, "Given context: " + context + ", is already suspended."); PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_STATE, "Given context: " + context + ", is already suspended.");
} }
} }
public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm) { public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm) {
canResume(context, rm); rm.setData(doCanStep(context, stepType));
rm.done();
} }
public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) { public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) {
assert context != null; assert context != null;
if (doCanResume(context)) { if (doCanStep(context, stepType)) {
fResumePending = true; final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
fStepping = true; final boolean vmWasSuspneded = fVMSuspended;
if (vmWasSuspneded) {
fVMResumePending = true;
} else {
fThreads.get(threadCtx.getID()).fResumePending = true;
}
AbstractPDACommand<PDACommandResult> stepCommand =
stepType == StepType.STEP_RETURN
? new PDAStepReturnCommand(fDMContext, threadCtx.getID())
: new PDAStepCommand(fDMContext, threadCtx.getID());
fCommandControl.queueCommand( fCommandControl.queueCommand(
new PDAStepCommand(fCommandControl.getProgramDMContext()), stepCommand,
new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleFailure() { protected void handleFailure() {
// If the step command failed, we no longer // If the step command failed, we no longer
// expect to receive a resumed event. // expect to receive a resumed event.
fResumePending = false; if (vmWasSuspneded) {
fStepping = false; 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<IExecutionDMContext[]> rm) { public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor<IExecutionDMContext[]> 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<IExecutionDMData> rm) { public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm) {
rm.setData( new ExecutionDMData(fStateChangeReason) ); 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(); rm.done();
} }
} }

View file

@ -13,6 +13,8 @@ package org.eclipse.dd.examples.pda.service;
import java.util.Hashtable; import java.util.Hashtable;
import org.eclipse.cdt.core.IAddress; 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.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.concurrent.Immutable;
@ -55,7 +57,7 @@ public class PDAStack extends AbstractDsfService implements IStack {
final private int fLevel; final private int fLevel;
FrameDMContext(String sessionId, IExecutionDMContext execDmc, int level) { FrameDMContext(String sessionId, PDAThreadDMContext execDmc, int level) {
super(sessionId, new IDMContext[] { execDmc }); super(sessionId, new IDMContext[] { execDmc });
fLevel = level; fLevel = level;
} }
@ -119,7 +121,7 @@ public class PDAStack extends AbstractDsfService implements IStack {
final private String fVariable; final private String fVariable;
VariableDMContext(String sessionId, IFrameDMContext frameCtx, String variable) { VariableDMContext(String sessionId, FrameDMContext frameCtx, String variable) {
super(sessionId, new IDMContext[] { frameCtx }); super(sessionId, new IDMContext[] { frameCtx });
fVariable = variable; fVariable = variable;
} }
@ -219,9 +221,18 @@ public class PDAStack extends AbstractDsfService implements IStack {
} }
public void getFrameData(final IFrameDMContext frameCtx, final DataRequestMonitor<IFrameDMData> rm) { public void getFrameData(final IFrameDMContext frameCtx, final DataRequestMonitor<IFrameDMData> 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. // Execute the PDA stack command, or retrieve the result from cache if already available.
fCommandCache.execute( fCommandCache.execute(
new PDAStackCommand(fCommandControl.getProgramDMContext()), new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()),
new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { 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 // however the argument context is a generic context type, so it could
// be an execution context, a frame, a variable, etc. Search the // be an execution context, a frame, a variable, etc. Search the
// hierarchy of the argument context to find the execution one. // hierarchy of the argument context to find the execution one.
final IExecutionDMContext execCtx = DMContexts.getAncestorOfType(context, IExecutionDMContext.class); final PDAThreadDMContext threadCtx =
if (execCtx == null) { DMContexts.getAncestorOfType(context, PDAThreadDMContext.class);
PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + context);
if (threadCtx == null) {
rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null));
rm.done();
return; return;
} }
// Execute the stack command and create the corresponding frame contexts. // Execute the stack command and create the corresponding frame contexts.
fCommandCache.execute( fCommandCache.execute(
new PDAStackCommand(fCommandControl.getProgramDMContext()), new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()),
new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
IFrameDMContext[] frameCtxs = new IFrameDMContext[getData().fFrames.length]; IFrameDMContext[] frameCtxs = new IFrameDMContext[getData().fFrames.length];
for (int i = 0; i < getData().fFrames.length; i++) { 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.setData(frameCtxs);
rm.done(); rm.done();
@ -268,10 +282,25 @@ public class PDAStack extends AbstractDsfService implements IStack {
}); });
} }
public void getLocals(final IFrameDMContext frameCtx, final DataRequestMonitor<IVariableDMContext[]> rm) { public void getLocals(IFrameDMContext context, final DataRequestMonitor<IVariableDMContext[]> rm) {
// Execute the stack command again. 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( fCommandCache.execute(
new PDAStackCommand(fCommandControl.getProgramDMContext()), new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()),
new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
@ -296,9 +325,18 @@ public class PDAStack extends AbstractDsfService implements IStack {
} }
public void getStackDepth(IDMContext context, int maxDepth, final DataRequestMonitor<Integer> rm) { public void getStackDepth(IDMContext context, int maxDepth, final DataRequestMonitor<Integer> 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. // Execute stack command and return the data's size.
fCommandCache.execute( fCommandCache.execute(
new PDAStackCommand(fCommandControl.getProgramDMContext()), new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()),
new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) { new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { 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 // however the argument context is a generic context type, so it could
// be an execution context, a frame, a variable, etc. Search the // be an execution context, a frame, a variable, etc. Search the
// hierarchy of the argument context to find the execution one. // 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) { if (execCtx == null) {
PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + context); PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + context);
return; return;

View file

@ -11,12 +11,16 @@
package org.eclipse.dd.examples.pda.service; package org.eclipse.dd.examples.pda.service;
import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; 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. * Event issued when the PDA debugger is started.
*/ */
public class PDAStartedEvent extends AbstractDMEvent<PDAProgramDMContext> { public class PDAStartedEvent extends AbstractDMEvent<IExecutionDMContext>
PDAStartedEvent(PDAProgramDMContext context) { implements IStartedDMEvent
{
PDAStartedEvent(PDAVirtualMachineDMContext context) {
super(context); super(context);
} }
} }

View file

@ -11,12 +11,16 @@
package org.eclipse.dd.examples.pda.service; package org.eclipse.dd.examples.pda.service;
import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; 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. * Event issued when the PDA debugger exits.
*/ */
public class PDATerminatedEvent extends AbstractDMEvent<PDAProgramDMContext> { public class PDATerminatedEvent extends AbstractDMEvent<IExecutionDMContext>
PDATerminatedEvent(PDAProgramDMContext context) { implements IExitedDMEvent
{
PDATerminatedEvent(PDAVirtualMachineDMContext context) {
super(context); super(context);
} }
} }

View file

@ -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);
}
}

View file

@ -14,12 +14,12 @@ import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.dd.dsf.datamodel.AbstractDMContext; import org.eclipse.dd.dsf.datamodel.AbstractDMContext;
import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; 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; import org.eclipse.dd.dsf.service.DsfSession;
/** /**
* Top-level Data Model context for the PDA debugger representing the PDA * Top-level Data Model context for the PDA debugger representing the while PDA
* program. * virtual machine.
* <p> * <p>
* The PDA debugger is a single-threaded application. Therefore this * The PDA debugger is a single-threaded application. Therefore this
* top level context implements IExecutionDMContext directly, hence 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. * service to install/remove breakpoints.
* </p> * </p>
* <p> * <p>
* Note: There should only be one instance of PDACommandControlDMContext created * Note: There should only be one instance of PDAVirtualMachineDMContext
* by each PDA command control, so its equals method defaults to using * created by each PDA command control, so its equals method defaults to using
* instance comparison. * instance comparison.
* </p> * </p>
*/ */
public class PDAProgramDMContext extends PlatformObject public class PDAVirtualMachineDMContext extends PlatformObject
implements IExecutionDMContext, IBreakpointsTargetDMContext implements IContainerDMContext, IBreakpointsTargetDMContext
{ {
final static IDMContext[] EMPTY_PARENTS_ARRAY = new IDMContext[0]; final static IDMContext[] EMPTY_PARENTS_ARRAY = new IDMContext[0];
final private String fSessionId; final private String fSessionId;
final private String fProgram; final private String fProgram;
public PDAProgramDMContext(String sessionId, String program) { public PDAVirtualMachineDMContext(String sessionId, String program) {
fSessionId = sessionId; fSessionId = sessionId;
fProgram = program; fProgram = program;
} }
@ -64,7 +64,7 @@ public class PDAProgramDMContext extends PlatformObject
@Override @Override
public String toString() { public String toString() {
return "PDA(" + getSessionId() + ")"; return "pda[" + getSessionId() + "]";
} }
/** /**

View file

@ -14,7 +14,7 @@ import org.eclipse.dd.dsf.concurrent.Immutable;
import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.debug.service.command.ICommand; import org.eclipse.dd.dsf.debug.service.command.ICommand;
import org.eclipse.dd.dsf.debug.service.command.ICommandResult; 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 * Base class for PDA commands. The PDA commands consist of a text request and
@ -27,7 +27,7 @@ abstract public class AbstractPDACommand<V extends PDACommandResult> implements
final private IDMContext fContext; final private IDMContext fContext;
final private String fRequest; final private String fRequest;
public AbstractPDACommand(PDAProgramDMContext context, String request) { public AbstractPDACommand(PDAVirtualMachineDMContext context, String request) {
fContext = context; fContext = context;
fRequest = request; fRequest = request;
} }

View file

@ -11,7 +11,7 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Clears any breakpoint set on given line
@ -25,7 +25,7 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
@Immutable @Immutable
public class PDAClearBreakpointCommand extends AbstractPDACommand<PDACommandResult> { public class PDAClearBreakpointCommand extends AbstractPDACommand<PDACommandResult> {
public PDAClearBreakpointCommand(PDAProgramDMContext context, int line) { public PDAClearBreakpointCommand(PDAVirtualMachineDMContext context, int line) {
super(context, "clear " + (line - 1)); super(context, "clear " + (line - 1));
} }

View file

@ -11,21 +11,24 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Retrieves data stack information
* *
* <pre> * <pre>
* C: data * C: data {thread_id}
* R: {value 1}|{value 2}|{value 3}|...| * R: {value 1}|{value 2}|{value 3}|...|
*
* Errors:
* error: invalid thread
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDADataCommand extends AbstractPDACommand<PDADataCommandResult> { public class PDADataCommand extends AbstractPDACommand<PDADataCommandResult> {
public PDADataCommand(PDAProgramDMContext context) { public PDADataCommand(PDAVirtualMachineDMContext context, int threadId) {
super(context, "data"); super(context, "data " + threadId);
} }
@Override @Override

View file

@ -11,24 +11,33 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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. * Returns from the current frame without executing the rest of instructions.
* *
* <pre> * <pre>
* C: drop * If VM running:
* C: drop {thread_id}
* R: ok * R: ok
* E: resumed drop * E: resumed {thread_id} drop
* E: suspended 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
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDADropFrameCommand extends AbstractPDACommand<PDACommandResult> { public class PDADropFrameCommand extends AbstractPDACommand<PDACommandResult> {
public PDADropFrameCommand(PDAProgramDMContext context) { public PDADropFrameCommand(PDAVirtualMachineDMContext context, int threadId) {
super(context, "drop"); super(context, "drop " + threadId);
} }
@Override @Override

View file

@ -11,17 +11,22 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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. * Sets what events cause the execution to stop.
* *
* <pre> * <pre>
* C: eval {instruction}%20{parameter}|{instruction}%20{parameter}|... * C: eval {thread_id} {instruction}%20{parameter}|{instruction}%20{parameter}|...
* R: ok * R: ok
* E: resume client * E: resumed {thread_id} client
* E: evalresult result * 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
* </pre> * </pre>
* *
* Where event_name could be <code>unimpinstr</code> or <code>nosuchlabel</code>. * Where event_name could be <code>unimpinstr</code> or <code>nosuchlabel</code>.
@ -29,8 +34,8 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
@Immutable @Immutable
public class PDAEvalCommand extends AbstractPDACommand<PDACommandResult> { public class PDAEvalCommand extends AbstractPDACommand<PDACommandResult> {
public PDAEvalCommand(PDAProgramDMContext context, String operation) { public PDAEvalCommand(PDAVirtualMachineDMContext context, int threadId, String operation) {
super(context, "eval " + operation); super(context, "eval " + threadId + " " + operation);
} }
@Override @Override

View file

@ -11,7 +11,7 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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. * Sets what events cause the execution to stop.
@ -30,7 +30,7 @@ public class PDAEventStopCommand extends AbstractPDACommand<PDACommandResult> {
public enum Event { UNIMPINSTR, NOSUCHLABEL }; public enum Event { UNIMPINSTR, NOSUCHLABEL };
public PDAEventStopCommand(PDAProgramDMContext context, Event event, boolean enable) { public PDAEventStopCommand(PDAVirtualMachineDMContext context, Event event, boolean enable) {
super(context, super(context,
"eventstop " + "eventstop " +
(event == Event.UNIMPINSTR ? "unimpinstr " : "nosuchlabel ") + (event == Event.UNIMPINSTR ? "unimpinstr " : "nosuchlabel ") +

View file

@ -11,7 +11,7 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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. * Instructs the debugger to exit.
@ -24,7 +24,7 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
@Immutable @Immutable
public class PDAExitCommand extends AbstractPDACommand<PDACommandResult> { public class PDAExitCommand extends AbstractPDACommand<PDACommandResult> {
public PDAExitCommand(PDAProgramDMContext context) { public PDAExitCommand(PDAVirtualMachineDMContext context) {
super(context, "exit"); super(context, "exit");
} }

View file

@ -11,21 +11,24 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Pops the top value from the data stack
* *
* <pre> * <pre>
* C: popdata * C: popdata {thread_id}
* R: ok * R: ok
*
* Errors:
* error: invalid thread
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDAPopDataCommand extends AbstractPDACommand<PDACommandResult> { public class PDAPopDataCommand extends AbstractPDACommand<PDACommandResult> {
public PDAPopDataCommand(PDAProgramDMContext context) { public PDAPopDataCommand(PDAVirtualMachineDMContext context, int threadId) {
super(context, "popdata"); super(context, "popdata " + threadId);
} }
@Override @Override

View file

@ -11,21 +11,24 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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. * Pushes the given value on top of the data stack.
* *
* <pre> * <pre>
* C: pushdata {value} * C: pushdata {thread_id} {value}
* R: ok * R: ok
*
* Errors:
* error: invalid thread
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDAPushDataCommand extends AbstractPDACommand<PDACommandResult> { public class PDAPushDataCommand extends AbstractPDACommand<PDACommandResult> {
public PDAPushDataCommand(PDAProgramDMContext context, int value) { public PDAPushDataCommand(PDAVirtualMachineDMContext context, int threadId, int value) {
super(context, "pushdata " + value); super(context, "pushdata " + threadId + " " + value);
} }
@Override @Override

View file

@ -11,22 +11,28 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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.
* *
* <pre> * <pre>
* C: resume * C: resume {thread_id}
* R: ok * 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
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDAResumeCommand extends AbstractPDACommand<PDACommandResult> { public class PDAResumeCommand extends AbstractPDACommand<PDACommandResult> {
public PDAResumeCommand(PDAProgramDMContext context) { public PDAResumeCommand(PDAVirtualMachineDMContext context, int threadId) {
super(context, "resume"); super(context, "resume " + threadId);
} }
@Override @Override

View file

@ -11,24 +11,35 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Sets a breakpoint at given line
* *
* <pre> * <pre>
* C: set {line_number} * Suspend a single thread:
* C: set {line_number} 0
* R: ok * R: ok
* C: resume * C: resume {thread_id}
* E: resumed client * E: resumed {thread_id} client
* E: suspended breakpoint line_number * 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
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDASetBreakpointCommand extends AbstractPDACommand<PDACommandResult> { public class PDASetBreakpointCommand extends AbstractPDACommand<PDACommandResult> {
public PDASetBreakpointCommand(PDAProgramDMContext context, int line) { public PDASetBreakpointCommand(PDAVirtualMachineDMContext context, int line, boolean stopVM) {
super(context, "set " + (line - 1)); super(context,
"set " +
(line - 1) + " " +
(stopVM ? "1" : "0"));
} }
@Override @Override

View file

@ -11,21 +11,24 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Sets a data value in the data stack at the given location
* *
* <pre> * <pre>
* C: setdata {index} {value} * C: setdata {thread_id} {index} {value}
* R: ok * R: ok
*
* Errors:
* error: invalid thread
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDASetDataCommand extends AbstractPDACommand<PDACommandResult> { public class PDASetDataCommand extends AbstractPDACommand<PDACommandResult> {
public PDASetDataCommand(PDAProgramDMContext context, int index, String value) { public PDASetDataCommand(PDAVirtualMachineDMContext context, int threadId, int index, String value) {
super(context, "setdata " + index + " " + value); super(context, "setdata " + threadId + " " + index + " " + value);
} }
@Override @Override

View file

@ -11,21 +11,24 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Sets a variable value
* *
* <pre> * <pre>
* C: setvar {frame_number} {variable} {value} * C: setvar {thread_id} {frame_number} {variable} {value}
* R: ok * R: ok
*
* Errors:
* error: invalid thread
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDASetVarCommand extends AbstractPDACommand<PDACommandResult> { public class PDASetVarCommand extends AbstractPDACommand<PDACommandResult> {
public PDASetVarCommand(PDAProgramDMContext context, int frame, String variable, String value) { public PDASetVarCommand(PDAVirtualMachineDMContext context, int threadId, int frame, String variable, String value) {
super(context, "setvar " + frame + " " + variable + " " + value); super(context, "setvar " + threadId + " " + frame + " " + variable + " " + value);
} }
@Override @Override

View file

@ -11,21 +11,24 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Retrieves command stack information
* *
* <pre> * <pre>
* C: stack * C: stack {thread_id}
* R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#... * R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#...
*
* Errors:
* error: invalid thread
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDAStackCommand extends AbstractPDACommand<PDAStackCommandResult> { public class PDAStackCommand extends AbstractPDACommand<PDAStackCommandResult> {
public PDAStackCommand(PDAProgramDMContext context) { public PDAStackCommand(PDAVirtualMachineDMContext context, int threadId) {
super(context, "stack"); super(context, "stack " + threadId);
} }
@Override @Override

View file

@ -11,23 +11,33 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Executes next instruction
* *
* <pre> * <pre>
* C: step * If VM running:
* C: step {thread_id}
* R: ok * R: ok
* E: resumed client * E: resumed {thread_id} client
* E: suspended step * 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
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDAStepCommand extends AbstractPDACommand<PDACommandResult> { public class PDAStepCommand extends AbstractPDACommand<PDACommandResult> {
public PDAStepCommand(PDAProgramDMContext context) { public PDAStepCommand(PDAVirtualMachineDMContext context, int threadId) {
super(context, "step"); super(context, "step " + threadId);
} }
@Override @Override

View file

@ -11,23 +11,33 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Executes instructions until the current subroutine is finished
* *
* <pre> * <pre>
* C: stepreturn * If VM running:
* C: stepreturn {thread_id}
* R: ok * R: ok
* E: resumed step * E: resumed {thread_id} client
* E: suspended step * 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
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDAStepReturnCommand extends AbstractPDACommand<PDACommandResult> { public class PDAStepReturnCommand extends AbstractPDACommand<PDACommandResult> {
public PDAStepReturnCommand(PDAProgramDMContext context) { public PDAStepReturnCommand(PDAVirtualMachineDMContext context, int threadId) {
super(context, "stepreturn"); super(context, "stepreturn " + threadId);
} }
@Override @Override

View file

@ -11,22 +11,28 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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.
* *
* <pre> * <pre>
* C: suspend * C: suspend {thread_id}
* R: ok * R: ok
* E: suspended client * E: suspended {thread_id} client
*
* Errors:
* error: invalid thread
error: vm already suspended
* error: thread already suspended
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDASuspendCommand extends AbstractPDACommand<PDACommandResult> { public class PDASuspendCommand extends AbstractPDACommand<PDACommandResult> {
public PDASuspendCommand(PDAProgramDMContext context) { public PDASuspendCommand(PDAVirtualMachineDMContext context, int threadId) {
super(context, "suspend"); super(context, "suspend " + threadId);
} }
@Override @Override

View file

@ -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
*
* <pre>
* C: vmresume
* R: ok
* E: vmresumed client
*
* Errors:
* error: vm already running
* </pre>
*/
@Immutable
public class PDAVMResumeCommand extends AbstractPDACommand<PDACommandResult> {
public PDAVMResumeCommand(PDAVirtualMachineDMContext context) {
super(context, "vmresume");
}
@Override
public PDACommandResult createResult(String resultText) {
return new PDACommandResult(resultText);
}
}

View file

@ -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
*
* <pre>
* C: vmsuspend
* R: ok
* E: vmsuspended client
*
* Errors:
* error: thread already suspended
* </pre>
*/
@Immutable
public class PDAVMSuspendCommand extends AbstractPDACommand<PDACommandResult> {
public PDAVMSuspendCommand(PDAVirtualMachineDMContext context) {
super(context, "vmsuspend");
}
@Override
public PDACommandResult createResult(String resultText) {
return new PDACommandResult(resultText);
}
}

View file

@ -11,21 +11,25 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Retrieves variable value
* *
* <pre> * <pre>
* C: var {frame_number} {variable_name} * C: var {thread_id} {frame_number} {variable_name}
* R: {variable_value} * R: {variable_value}
*
* Errors:
* error: invalid thread
* error: variable undefined
* </pre> * </pre>
*/ */
@Immutable @Immutable
public class PDAVarCommand extends AbstractPDACommand<PDACommandResult> { public class PDAVarCommand extends AbstractPDACommand<PDACommandResult> {
public PDAVarCommand(PDAProgramDMContext context, int frameId, String name) { public PDAVarCommand(PDAVirtualMachineDMContext context, int threadId, int frameId, String name) {
super(context, "var " + frameId + " " + name); super(context, "var " + threadId + " " + frameId + " " + name);
} }
@Override @Override

View file

@ -11,7 +11,7 @@
package org.eclipse.dd.examples.pda.service.commands; package org.eclipse.dd.examples.pda.service.commands;
import org.eclipse.dd.dsf.concurrent.Immutable; 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 * Sets a watchpoint on a given variable
@ -19,9 +19,9 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
* <pre> * <pre>
* C: watch {function}::{variable_name} {watch_operation} * C: watch {function}::{variable_name} {watch_operation}
* R: ok * R: ok
* C: resume * C: vmresume
* R: resume client * R: vmresumed client
* E: suspended watch {watch_operation} {function}::{variable_name} * E: vmsuspended {thread_id} watch {watch_operation} {function}::{variable_name}
* </pre> * </pre>
*/ */
@Immutable @Immutable
@ -42,7 +42,7 @@ public class PDAWatchCommand extends AbstractPDACommand<PDACommandResult> {
} }
} }
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)); super(context, "watch " + function+ "::" + variable + " " + getWatchOperationCode(operation));
} }

View file

@ -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. // Test sending the command and checking all listeners were called.
Query<PDACommandResult> sendCommandQuery = new Query<PDACommandResult>() { Query<PDACommandResult> sendCommandQuery = new Query<PDACommandResult>() {

View file

@ -105,7 +105,7 @@ public class CommandControlTestsBase {
protected void sendCommand(String command, String expectedResult) throws Throwable { 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. // Test sending the command and checking all listeners were called.
Query<PDACommandResult> sendCommandQuery = new Query<PDACommandResult>() { Query<PDACommandResult> sendCommandQuery = new Query<PDACommandResult>() {

View file

@ -10,7 +10,7 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.dd.tests.pda.service.command; 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.AbstractPDACommand;
import org.eclipse.dd.examples.pda.service.commands.PDACommandResult; 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<PDACommandResult> { class PDATestCommand extends AbstractPDACommand<PDACommandResult> {
PDATestCommand(PDAProgramDMContext context, String command) { PDATestCommand(PDAVirtualMachineDMContext context, String command) {
super(context, command); super(context, command);
} }

View file

@ -30,7 +30,7 @@ public class Test1 extends CommandControlTestsBase {
@Test @Test
public void testRun() throws Throwable { public void testRun() throws Throwable {
sendCommand("resume"); sendCommand("vmresume");
expectOutput("\"hello\""); expectOutput("\"hello\"");
expectOutput("\"barfoo\""); expectOutput("\"barfoo\"");
expectOutput("\"first\""); expectOutput("\"first\"");

View file

@ -31,79 +31,161 @@ public class Test2 extends CommandControlTestsBase {
@Test @Test
public void testCommonDebugCommands() throws Throwable { public void testCommonDebugCommands() throws Throwable {
expectEvent("started"); expectEvent("started 1");
// test step // test step
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
// test breakpoint // test breakpoint
sendCommand("set 4"); sendCommand("set 4 1");
sendCommand("data", "6|"); sendCommand("data 1", "6|");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("suspended breakpoint 4"); expectEvent("vmsuspended 1 breakpoint 4");
// test data stack // test data stack
sendCommand("data", "6|7|8|9|"); sendCommand("data 1", "6|7|8|9|");
sendCommand("popdata"); sendCommand("popdata 1");
sendCommand("data", "6|7|8|"); sendCommand("data 1", "6|7|8|");
sendCommand("pushdata 11"); sendCommand("pushdata 1 11");
sendCommand("data", "6|7|8|11|"); sendCommand("data 1", "6|7|8|11|");
sendCommand("setdata 1 2"); sendCommand("setdata 1 1 2");
sendCommand("data", "6|2|8|11|"); sendCommand("data 1", "6|2|8|11|");
// test call stack // test call stack
sendCommand("set 12"); sendCommand("set 12 1");
sendCommand("set 19"); sendCommand("set 19 1");
sendCommand("stepreturn"); sendCommand("stepreturn 1");
expectEvent("resumed client"); expectEvent("vmresumed step");
expectEvent("suspended breakpoint 12"); expectEvent("vmsuspended 1 breakpoint 12");
sendCommand("clear 19"); sendCommand("clear 19");
sendCommand("stack", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" ); sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" );
sendCommand("stepreturn"); sendCommand("stepreturn 1");
expectEvent("resumed client"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("stack", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" ); sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" );
sendCommand("stepreturn"); sendCommand("stepreturn 1");
expectEvent("resumed client"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("stack", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" ); sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" );
sendCommand("set 6"); sendCommand("set 6 1");
sendCommand("stepreturn"); sendCommand("stepreturn 1");
expectEvent("resumed client"); expectEvent("vmresumed step");
expectEvent("suspended breakpoint 6"); expectEvent("vmsuspended 1 breakpoint 6");
// test set and clear // test set and clear
sendCommand("set 27"); sendCommand("set 27 1");
sendCommand("set 29"); sendCommand("set 29 1");
sendCommand("set 33"); sendCommand("set 33 1");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("suspended breakpoint 33"); expectEvent("vmsuspended 1 breakpoint 33");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("suspended breakpoint 27"); expectEvent("vmsuspended 1 breakpoint 27");
sendCommand("clear 33"); sendCommand("clear 33");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("suspended breakpoint 29"); expectEvent("vmsuspended 1 breakpoint 29");
// test var and setvar // test var and setvar
sendCommand("set 47"); sendCommand("set 47 1");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("suspended breakpoint 47"); expectEvent("vmsuspended 1 breakpoint 47");
sendCommand("var 1 b", "4"); sendCommand("var 1 1 b", "4");
sendCommand("var 2 b", "2"); sendCommand("var 1 2 b", "2");
sendCommand("var 1 a", "0"); sendCommand("var 1 1 a", "0");
sendCommand("setvar 1 a 99"); sendCommand("setvar 1 1 a 99");
sendCommand("data", "6|2|8|11|27|1|4|"); sendCommand("data 1", "6|2|8|11|27|1|4|");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("var 1 a", "99"); sendCommand("var 1 1 a", "99");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("data", "6|2|8|11|27|1|4|99|"); 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 // test exit
sendCommand("exit"); sendCommand("exit");
expectEvent("terminated"); 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");
}
} }

View file

@ -31,43 +31,59 @@ public class Test3 extends CommandControlTestsBase {
@Test @Test
public void testUncaughtEvents() throws Throwable { public void testUncaughtEvents() throws Throwable {
expectEvent("started"); expectEvent("started 1");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("unimplemented instruction foobar"); expectEvent("unimplemented instruction foobar");
expectEvent("no such label zippy"); expectEvent("no such label zippy");
expectEvent("no such label swishy");
expectEvent("exited 1");
expectEvent("terminated"); expectEvent("terminated");
} }
@Test @Test
public void testCaughtUnimpinstrEvents() throws Throwable { public void testCaughtUnimpinstrEvents() throws Throwable {
expectEvent("started"); expectEvent("started 1");
sendCommand("eventstop unimpinstr 1"); sendCommand("eventstop unimpinstr 1");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("unimplemented instruction foobar"); expectEvent("unimplemented instruction foobar");
expectEvent("suspended event unimpinstr"); expectEvent("vmsuspended 1 event unimpinstr");
sendCommand("eventstop unimpinstr 0"); sendCommand("eventstop unimpinstr 0");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("unimplemented instruction foobar"); expectEvent("unimplemented instruction foobar");
expectEvent("no such label zippy"); expectEvent("no such label zippy");
expectEvent("no such label swishy");
expectEvent("exited 1");
expectEvent("terminated"); expectEvent("terminated");
} }
@Test @Test
public void testCaughtNosuchlabelEvents() throws Throwable { public void testCaughtNosuchlabelEvents() throws Throwable {
expectEvent("started"); expectEvent("started 1");
sendCommand("eventstop nosuchlabel 1"); sendCommand("eventstop nosuchlabel 1");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("unimplemented instruction foobar"); expectEvent("unimplemented instruction foobar");
expectEvent("no such label zippy"); expectEvent("no such label zippy");
expectEvent("suspended event nosuchlabel"); expectEvent("vmsuspended 1 event nosuchlabel");
sendCommand("eventstop nosuchlabel 0"); sendCommand("eventstop nosuchlabel 0");
sendCommand("resume"); sendCommand("set 11 1");
expectEvent("resumed client"); sendCommand("vmresume");
expectEvent("vmresumed client");
expectEvent("no such label zippy"); 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"); expectEvent("terminated");
} }

View file

@ -31,49 +31,54 @@ public class Test6 extends CommandControlTestsBase {
@Test @Test
public void testWatchPoints() throws Throwable { public void testWatchPoints() throws Throwable {
expectEvent("started"); expectEvent("started 1");
sendCommand("watch inner::a 1"); sendCommand("watch inner::a 1");
sendCommand("watch main::a 2"); sendCommand("watch main::a 2");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("suspended watch write main::a"); expectEvent("vmsuspended 1 watch write main::a");
sendCommand("stack", fProgram + "|4|main|a|b"); sendCommand("stack 1", fProgram + "|4|main|a|b");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("suspended watch read inner::a"); expectEvent("vmsuspended 1 watch read inner::a");
sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|25|inner|a|c"); sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|25|inner|a|c");
sendCommand("watch inner::a 0"); sendCommand("watch inner::a 0");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); expectEvent("vmresumed client");
expectEvent("exited 1");
expectEvent("terminated"); expectEvent("terminated");
} }
@Test @Test
public void testEval() throws Throwable { public void testEval() throws Throwable {
expectEvent("started"); expectEvent("started 1");
sendCommand("set 25");
sendCommand("resume");
expectEvent("resumed client");
expectEvent("suspended breakpoint 25");
sendCommand("eval push%204|push%205|add"); sendCommand("eval 1 test_error", "error: cannot evaluate while vm is suspended");
expectEvent("resumed client");
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("evalresult 9");
expectEvent("suspended eval"); expectEvent("suspended 1 eval");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("resumed 1 step");
expectEvent("suspended step"); expectEvent("suspended 1 step");
sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c"); sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c");
sendCommand("data", "4|4|"); sendCommand("data 1", "4|4|");
sendCommand("eval call%20other"); sendCommand("eval 1 call%20other");
expectEvent("resumed client"); expectEvent("resumed 1 eval");
expectEvent("evalresult 15"); expectEvent("evalresult 15");
expectEvent("suspended eval"); expectEvent("suspended 1 eval");
sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c"); sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c");
sendCommand("data", "4|4|"); sendCommand("data 1", "4|4|");
sendCommand("resume"); sendCommand("resume 1");
expectEvent("resumed client"); expectEvent("resumed 1 client");
expectEvent("exited 1");
expectEvent("terminated"); expectEvent("terminated");
} }
} }

View file

@ -31,39 +31,63 @@ public class Test8 extends CommandControlTestsBase {
@Test @Test
public void testDropFrame() throws Throwable { public void testDropFrame() throws Throwable {
expectEvent("started"); expectEvent("started 1");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c"); sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c");
sendCommand("drop"); sendCommand("drop 1");
expectEvent("resumed drop"); expectEvent("vmresumed drop");
expectEvent("suspended drop"); expectEvent("vmsuspended 1 drop");
sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|7|inner|b"); sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|7|inner|b");
sendCommand("step"); sendCommand("step 1");
expectEvent("resumed step"); expectEvent("vmresumed step");
expectEvent("suspended step"); expectEvent("vmsuspended 1 step");
sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2"); sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2");
sendCommand("resume"); sendCommand("vmresume");
expectEvent("resumed client"); 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"); expectEvent("terminated");
} }

View file

@ -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");
}
}

View file

@ -68,12 +68,11 @@ public class ContainerVMNode extends AbstractContainerVMNode
@Override @Override
protected void updateLabelInSessionThread(ILabelUpdate[] updates) { protected void updateLabelInSessionThread(final ILabelUpdate update) {
for (final ILabelUpdate update : updates) {
final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
if ( runControl == null ) { if ( runControl == null ) {
handleFailedUpdate(update); handleFailedUpdate(update);
continue; return;
} }
final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class); final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class);
@ -100,7 +99,6 @@ public class ContainerVMNode extends AbstractContainerVMNode
} }
}); });
} }
}
@Override @Override
public int getDeltaFlags(Object e) { public int getDeltaFlags(Object e) {

View file

@ -11,42 +11,21 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.dd.gdb.internal.ui.viewmodel.launch; 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.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.datamodel.DMContexts; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractLaunchVMProvider;
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.LaunchRootVMNode; 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.StackFramesVMNode;
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StandardProcessVMNode; 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.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; 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.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.GDBExitedEvent;
import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.GDBStartedEvent; 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.InferiorExitedDMEvent;
import org.eclipse.dd.mi.service.command.MIInferiorProcess.InferiorStartedDMEvent; 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.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchesListener2; import org.eclipse.debug.core.ILaunchesListener2;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; 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") @SuppressWarnings("restriction")
public class LaunchVMProvider extends AbstractDMVMProvider public class LaunchVMProvider extends AbstractLaunchVMProvider
implements IDebugEventSetListener, ILaunchesListener2 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<IExecutionDMContext,ScheduledFuture<?>> fRefreshStackFramesFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
@ThreadSafe @ThreadSafe
public LaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) public LaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session)
{ {
@ -89,85 +61,6 @@ public class LaunchVMProvider extends AbstractDMVMProvider
DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); 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 @Override
public void dispose() { public void dispose() {
@ -176,42 +69,6 @@ public class LaunchVMProvider extends AbstractDMVMProvider
super.dispose(); 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 @Override
protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
@ -223,22 +80,7 @@ public class LaunchVMProvider extends AbstractDMVMProvider
{ {
return false; return false;
} }
return super.canSkipHandlingEvent(newEvent, 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;
} }
} }