From e31d06b0030d8177aa0b456bbe5f4898e872ee7e Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Tue, 5 Jan 2010 23:51:29 +0000 Subject: [PATCH] [298909] - [launch] DSF suspend trigger susceptible to race conditions --- dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml | 10 + .../gdb/internal/ui/GdbAdapterFactory.java | 5 +- .../gdb/internal/ui/GdbSuspendTrigger.java | 81 ++++++ .../debug/ui/contexts/DsfSuspendTrigger.java | 233 +++++++++++++++++- .../plugin.xml | 2 +- .../dsf/pda/ui/PDASuspendTrigger.java | 56 +++++ .../dsf/pda/ui/SessionAdapterSet.java | 12 +- .../pda/launch/PDAServicesInitSequence.java | 15 +- .../dsf/pda/service/PDAExpressions.java | 1 + .../examples/dsf/pda/service/PDAStack.java | 1 + 10 files changed, 389 insertions(+), 27 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbSuspendTrigger.java create mode 100644 dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDASuspendTrigger.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml index bc4821f5cbd..42f4bf9b040 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml @@ -345,5 +345,15 @@ id="org.eclipse.cdt.dsf.gdb.ui.GdbDebugTextHover"> + + + + + + diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java index e7da6be59fe..018c5a329fe 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java @@ -29,7 +29,6 @@ import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepIntoCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepOverCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepReturnCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfSuspendCommand; -import org.eclipse.cdt.dsf.debug.ui.contexts.DsfSuspendTrigger; import org.eclipse.cdt.dsf.debug.ui.sourcelookup.DsfSourceDisplayAdapter; import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController; import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.DefaultRefreshAllTarget; @@ -99,7 +98,7 @@ public class GdbAdapterFactory final GdbConnectCommand fConnectCommand; final GdbDisconnectCommand fDisconnectCommand; final IDebugModelProvider fDebugModelProvider; - final DsfSuspendTrigger fSuspendTrigger; + final GdbSuspendTrigger fSuspendTrigger; final GdbSteppingModeTarget fSteppingModeTarget; final IModelSelectionPolicyFactory fModelSelectionPolicyFactory; final SteppingController fSteppingController; @@ -137,7 +136,7 @@ public class GdbAdapterFactory fTerminateCommand = new DsfTerminateCommand(session); fConnectCommand = new GdbConnectCommand(session); fDisconnectCommand = new GdbDisconnectCommand(session); - fSuspendTrigger = new DsfSuspendTrigger(session, fLaunch); + fSuspendTrigger = new GdbSuspendTrigger(session, fLaunch); fModelSelectionPolicyFactory = new DefaultDsfModelSelectionPolicyFactory(); fRefreshAllTarget = new DefaultRefreshAllTarget(); fReverseToggleTarget = new GdbReverseToggleCommand(session); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbSuspendTrigger.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbSuspendTrigger.java new file mode 100644 index 00000000000..53f43ebe237 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbSuspendTrigger.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * 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.cdt.dsf.gdb.internal.ui; + +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IProcesses; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.debug.ui.contexts.DsfSuspendTrigger; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.ILaunch; + +/** + * @since 2.1 + */ +public class GdbSuspendTrigger extends DsfSuspendTrigger { + + public GdbSuspendTrigger(DsfSession session, ILaunch launch) { + super(session, launch); + } + + @Override + protected void getLaunchTopContainers(final DataRequestMonitor rm) { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + IProcesses processService = getServicesTracker().getService(IProcesses.class); + ICommandControlService controlService = getServicesTracker().getService(ICommandControlService.class); + if (processService == null || controlService == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Not available", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + processService.getProcessesBeingDebugged( + controlService.getContext(), + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm) { + @Override + public void handleSuccess() { + IContainerDMContext[] containers = new IContainerDMContext[getData().length]; + for (int i = 0; i < containers.length; i++) { + if (getData()[i] instanceof IContainerDMContext) { + containers[i] = (IContainerDMContext)getData()[i]; + } else { + // By convention the processes should be containers, but the API + // does not enforce this. + assert false; + rm.setData(new IContainerDMContext[0]); + rm.done(); + return; + } + + } + rm.setData(containers); + rm.done(); + } + }); + } + }); + } catch (RejectedExecutionException e) { + rm.setStatus(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Not available", e)); //$NON-NLS-1$ + rm.done(); + } + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/contexts/DsfSuspendTrigger.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/contexts/DsfSuspendTrigger.java index f8f853cb079..af47331e64b 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/contexts/DsfSuspendTrigger.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/contexts/DsfSuspendTrigger.java @@ -13,11 +13,19 @@ package org.eclipse.cdt.dsf.debug.ui.contexts; import java.util.concurrent.RejectedExecutionException; import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.ThreadSafe; +import org.eclipse.cdt.dsf.datamodel.DataModelInitializedEvent; import org.eclipse.cdt.dsf.debug.service.IRunControl; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; @@ -45,8 +53,9 @@ public class DsfSuspendTrigger implements ISuspendTrigger { private final DsfSession fSession; private final ILaunch fLaunch; - private boolean fDisposed = false; + private volatile boolean fDisposed = false; private boolean fEventListenerRegisterd = false; + private final DsfServicesTracker fServicesTracker; @ThreadSafe private final ListenerList fListeners = new ListenerList(); @@ -55,6 +64,7 @@ public class DsfSuspendTrigger implements ISuspendTrigger { public DsfSuspendTrigger(DsfSession session, ILaunch launch) { fSession = session; fLaunch = launch; + fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), fSession.getId()); try { fSession.getExecutor().execute(new DsfRunnable() { public void run() { @@ -68,28 +78,93 @@ public class DsfSuspendTrigger implements ISuspendTrigger { } @ThreadSafe - public void addSuspendTriggerListener(ISuspendTriggerListener listener) { - if (fListeners != null) { - fListeners.add(listener); - } + public void addSuspendTriggerListener(final ISuspendTriggerListener listener) { + fListeners.add(listener); + + // Check if an execution context in the model is already suspended. + // If so notify the listener. + getIsLaunchSuspended(new DataRequestMonitor(ImmediateExecutor.getInstance(), null) { + @Override + protected void handleSuccess() { + if (!fDisposed && getData().booleanValue()) { + listener.suspended(fLaunch, null); + } + } + }); } @ThreadSafe public void removeSuspendTriggerListener(ISuspendTriggerListener listener) { - if (fListeners != null) { - fListeners.remove(listener); - } + fListeners.remove(listener); } + @ThreadSafe public void dispose() { if (fEventListenerRegisterd) { fSession.removeServiceEventListener(this); } + fServicesTracker.dispose(); fDisposed = true; } + /** + * @noreference This method is not intended to be referenced by clients. + */ @DsfServiceEventHandler public void eventDispatched(IRunControl.ISuspendedDMEvent e) { + fireSuspended(null); + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + @DsfServiceEventHandler + public void eventDispatched(DataModelInitializedEvent e) { + getIsLaunchSuspended(new DataRequestMonitor(ImmediateExecutor.getInstance(), null) { + @Override + protected void handleSuccess() { + if (!fDisposed && getData().booleanValue()) { + fireSuspended(null); + } + } + }); + } + + /** + * Returns the services tracker used by the suspend trigger. + * @since 2.1 + */ + protected DsfServicesTracker getServicesTracker() { + return fServicesTracker; + } + + /** + * Returns the launch for this suspend trigger. + * @since 2.1 + */ + @ThreadSafe + protected ILaunch getLaunch() { + return fLaunch; + } + + /** + * Returns the DSF session for this suspend trigger. + * @since 2.1 + */ + @ThreadSafe + protected DsfSession getSession() { + return fSession; + } + + /** + * Notifies the listeners that a suspend event was received. + * + * @param context + * + * @since 2.1 + */ + @ThreadSafe + protected void fireSuspended(final Object context) { final Object[] listeners = fListeners.getListeners(); if (listeners.length != 0) { new Job("DSF Suspend Trigger Notify") { //$NON-NLS-1$ @@ -104,7 +179,7 @@ public class DsfSuspendTrigger implements ISuspendTrigger { final ISuspendTriggerListener listener = (ISuspendTriggerListener) listeners[i]; SafeRunner.run(new ISafeRunnable() { public void run() throws Exception { - listener.suspended(fLaunch, null); + listener.suspended(fLaunch, context); } public void handleException(Throwable exception) { @@ -119,5 +194,145 @@ public class DsfSuspendTrigger implements ISuspendTrigger { }.schedule(); } } + + /** + * Retrieves the top-level containers for this launch. This method should + * be overriden by specific debugger integrations. + * @param rm + * + * @since 2.1 + */ + @ThreadSafe + protected void getLaunchTopContainers(DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "Not implemented.", null)); //$NON-NLS-1$ + rm.done(); + } + + /** + * Checks if the given launch is currently suspended. + * + * @param rm Request monitor. + * + * @since 2.1 + */ + @ThreadSafe + private void getIsLaunchSuspended(final DataRequestMonitor rm) { + getLaunchTopContainers(new DataRequestMonitor(fSession.getExecutor(), rm) { + @Override + protected void handleSuccess() { + final CountingRequestMonitor crm = new CountingRequestMonitor(fSession.getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (rm.getData() == null) { + rm.setData(Boolean.FALSE); + } + rm.done(); + }; + }; + int count = 0; + for (final IContainerDMContext containerCtx : getData()) { + getIsContainerSuspended(containerCtx, new DataRequestMonitor(ImmediateExecutor.getInstance(), crm) { + @Override + protected void handleSuccess() { + if (getData().booleanValue()) { + rm.setData(Boolean.TRUE); + } + crm.done(); + }; + }); + count++; + } + crm.setDoneCount(count); + } + }); + } + /** + * Recursively checks if the given container or any of its execution + * contexts are suspended. + * + * @param container Container to check. + * @param rm Request monitor. + * + * @since 2.1 + */ + @ConfinedToDsfExecutor("fSession.getExecutor()") + private void getIsContainerSuspended(final IContainerDMContext container, final DataRequestMonitor rm) { + // Check if run control service is still available. + IRunControl rc = fServicesTracker.getService(IRunControl.class); + if (rc == null) { + rm.setData(Boolean.FALSE); + rm.done(); + return; + } + + // Check if container is suspended. If so, stop searching. + if (rc.isSuspended(container)) { + rm.setData(Boolean.TRUE); + rm.done(); + return; + } + + // Retrieve the execution contexts and check if any of them are suspended. + rc.getExecutionContexts( + container, + new DataRequestMonitor(fSession.getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Check if run control service is still available. + IRunControl rc = fServicesTracker.getService(IRunControl.class); + if (rc == null) { + rm.setData(Boolean.FALSE); + rm.done(); + return; + } + + // If any of the execution contexts are suspended, stop searching + boolean hasContainers = false; + for (IExecutionDMContext execCtx : getData()) { + if (rc.isSuspended(execCtx)) { + rm.setData(Boolean.TRUE); + rm.done(); + return; + } + hasContainers = hasContainers || execCtx instanceof IContainerDMContext; + } + + // If any of the returned contexts were containers, check them recursively. + if (hasContainers) { + final CountingRequestMonitor crm = new CountingRequestMonitor(fSession.getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (rm.getData() == null) { + rm.setData(Boolean.FALSE); + } + rm.done(); + }; + }; + int count = 0; + for (IExecutionDMContext execCtx : getData()) { + if (execCtx instanceof IContainerDMContext) { + getIsContainerSuspended( + (IContainerDMContext)execCtx, + new DataRequestMonitor(ImmediateExecutor.getInstance(), crm) { + @Override + protected void handleSuccess() { + if (getData().booleanValue()) { + rm.setData(Boolean.TRUE); + } + crm.done(); + }; + }); + count++; + } + } + crm.setDoneCount(count); + } else { + rm.setData(Boolean.FALSE); + rm.done(); + } + } + }); + } + } diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/plugin.xml b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/plugin.xml index 0f83e6b5f9b..2a0a9b3d948 100644 --- a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/plugin.xml +++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/plugin.xml @@ -70,7 +70,7 @@ point="org.eclipse.debug.ui.contextViewBindings"> + viewId="org.eclipse.debug.ui.ExpressionView"/> rm) { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + PDACommandControl control = + getServicesTracker().getService(PDACommandControl.class); + if (control != null) { + rm.setData(new IContainerDMContext[] { control.getContext() }); + } else { + rm.setStatus(new Status(IStatus.ERROR, PDAUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Not available", null)); + } + rm.done(); + + } + }); + } catch (RejectedExecutionException e) { + rm.setStatus(new Status(IStatus.ERROR, PDAUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Not available", e)); + rm.done(); + } + } +} diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/SessionAdapterSet.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/SessionAdapterSet.java index 6b5d01dd710..d7018fb07e6 100644 --- a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/SessionAdapterSet.java +++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/SessionAdapterSet.java @@ -10,24 +10,19 @@ *******************************************************************************/ package org.eclipse.cdt.examples.dsf.pda.ui; -import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.ui.actions.DsfResumeCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepIntoCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepOverCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepReturnCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfSuspendCommand; -import org.eclipse.cdt.dsf.debug.ui.contexts.DsfSuspendTrigger; import org.eclipse.cdt.dsf.debug.ui.sourcelookup.DsfSourceDisplayAdapter; import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController; import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.DefaultDsfModelSelectionPolicyFactory; -import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.DefaultDsfSelectionPolicy; import org.eclipse.cdt.dsf.service.DsfSession; -import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; import org.eclipse.cdt.examples.dsf.pda.PDAPlugin; import org.eclipse.cdt.examples.dsf.pda.launch.PDALaunch; import org.eclipse.cdt.examples.dsf.pda.ui.actions.PDATerminateCommand; import org.eclipse.cdt.examples.dsf.pda.ui.viewmodel.PDAVMAdapter; -import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.commands.IResumeHandler; import org.eclipse.debug.core.commands.IStepIntoHandler; import org.eclipse.debug.core.commands.IStepOverHandler; @@ -36,10 +31,7 @@ import org.eclipse.debug.core.commands.ISuspendHandler; import org.eclipse.debug.core.commands.ITerminateHandler; import org.eclipse.debug.core.model.IDebugModelProvider; import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; -import org.eclipse.debug.ui.IDebugUIConstants; import org.eclipse.debug.ui.sourcelookup.ISourceDisplay; /** @@ -59,7 +51,7 @@ class SessionAdapterSet { final DsfSuspendCommand fSuspendCommand; final DsfResumeCommand fResumeCommand; final PDATerminateCommand fTerminateCommand; - final DsfSuspendTrigger fSuspendTrigger; + final PDASuspendTrigger fSuspendTrigger; // Adapters for integration with other UI actions final IDebugModelProvider fDebugModelProvider; @@ -96,7 +88,7 @@ class SessionAdapterSet { fSuspendCommand = new DsfSuspendCommand(session); fResumeCommand = new DsfResumeCommand(session); fTerminateCommand = new PDATerminateCommand(session); - fSuspendTrigger = new DsfSuspendTrigger(session, fLaunch); + fSuspendTrigger = new PDASuspendTrigger(session, fLaunch); session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand); session.registerModelAdapter(IStepOverHandler.class, fStepOverCommand); diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java index d993cf54276..b996c48f255 100644 --- a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java +++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java @@ -12,6 +12,7 @@ package org.eclipse.cdt.examples.dsf.pda.launch; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.Sequence; +import org.eclipse.cdt.dsf.datamodel.DataModelInitializedEvent; import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.examples.dsf.pda.service.PDABackend; @@ -105,12 +106,18 @@ public class PDAServicesInitSequence extends Sequence { new PDARegisters(fSession).initialize(requestMonitor); } }, - new Step() { + /* + * Indicate that the Data Model has been filled. This will trigger the Debug view to expand. + */ + new Step() { @Override - public void execute(RequestMonitor requestMonitor) { - fRunControl.resume(fCommandControl.getContext(), requestMonitor); + public void execute(final RequestMonitor requestMonitor) { + fSession.dispatchEvent( + new DataModelInitializedEvent(fCommandControl.getContext()), + fCommandControl.getProperties()); + requestMonitor.done(); } - }, + } }; // Sequence input parameters, used in initializing services. diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAExpressions.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAExpressions.java index c4dc84407e9..10f468723cf 100644 --- a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAExpressions.java +++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAExpressions.java @@ -192,6 +192,7 @@ public class PDAExpressions extends AbstractDsfService implements ICachingServic fCommandControl = getServicesTracker().getService(PDACommandControl.class); fStack = getServicesTracker().getService(PDAStack.class); fCommandCache = new CommandCache(getSession(), fCommandControl); + fCommandCache.setContextAvailable(fCommandControl.getContext(), true); getSession().addServiceEventListener(this, null); diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStack.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStack.java index 5e86e56cb34..eb09f7029ba 100644 --- a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStack.java +++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStack.java @@ -207,6 +207,7 @@ public class PDAStack extends AbstractDsfService implements IStack, ICachingServ // Create the commands cache fCommandCache = new CommandCache(getSession(), fCommandControl); + fCommandCache.setContextAvailable(fCommandControl.getContext(), true); // Register to listen for run control events, to clear cache accordingly. getSession().addServiceEventListener(this, null);