diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java index 5041ea27712..1ba4920289c 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java @@ -70,8 +70,11 @@ public abstract class AbstractContainerVMNode extends AbstractDMVMNode implement { return IModelDelta.CONTENT; } else if (e instanceof IContainerSuspendedDMEvent) { - return IModelDelta.CONTENT; - } else if (e instanceof ISteppingTimedOutEvent && + // no change, update happens on FullStackRefreshEvent + return IModelDelta.NO_CHANGE; + } else if (e instanceof FullStackRefreshEvent) { + return IModelDelta.CONTENT; + } else if (e instanceof ISteppingTimedOutEvent && ((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) { return IModelDelta.CONTENT; @@ -93,8 +96,10 @@ public abstract class AbstractContainerVMNode extends AbstractDMVMNode implement { parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); } else if (e instanceof IContainerSuspendedDMEvent) { - parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); - } else if (e instanceof ISteppingTimedOutEvent && + // do nothing + } else if (e instanceof FullStackRefreshEvent) { + parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + } else if (e instanceof ISteppingTimedOutEvent && ((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) { parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java index 5cc2bb90f49..b111973f084 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java @@ -119,6 +119,16 @@ public abstract class AbstractThreadVMNode extends AbstractDMVMNode // a delta for all the threads. rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ rm.done(); + return; + } else if (e instanceof FullStackRefreshEvent && + ((FullStackRefreshEvent)e).getDMContext() instanceof IContainerDMContext) + { + // The step sequence end event occured on a container and not on a thread. Do not + // return a context for this event, which will force the view model to generate + // a delta for all the threads. + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ + rm.done(); + return; } else if (e instanceof ModelProxyInstalledEvent) { getThreadVMCForModelProxyInstallEvent( parentDelta, @@ -220,6 +230,9 @@ public abstract class AbstractThreadVMNode extends AbstractDMVMNode { return IModelDelta.CONTENT; } else if (e instanceof ISuspendedDMEvent) { + // no change, update happens on FullStackRefreshEvent + return IModelDelta.NO_CHANGE; + } else if (e instanceof FullStackRefreshEvent) { return IModelDelta.CONTENT; } else if (e instanceof ISteppingTimedOutEvent && !(((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) ) @@ -244,8 +257,11 @@ public abstract class AbstractThreadVMNode extends AbstractDMVMNode parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); rm.done(); } else if (e instanceof ISuspendedDMEvent) { + // no change + rm.done(); + } else if (e instanceof FullStackRefreshEvent) { parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); - rm.done(); + rm.done(); } else if (e instanceof ISteppingTimedOutEvent && !(((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) ) { diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java new file mode 100644 index 00000000000..9c9d5120fbf --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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.dsf.debug.internal.provisional.ui.viewmodel.launch; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.dd.dsf.ui.viewmodel.update.AutomaticUpdatePolicy; +import org.eclipse.dd.dsf.ui.viewmodel.update.IElementUpdateTester; +import org.eclipse.jface.viewers.TreePath; + +/** + * Automatic update strategy specialized for delayed full stack frame updates. The + * strategy can operate in lazy mode where only the top stack frame is + * invalidated, while in non-lazy mode everything is invalidated. + */ +public class DelayedStackRefreshUpdatePolicy extends AutomaticUpdatePolicy { + + private static final class DelayedStackRefreshUpdateTester implements IElementUpdateTester { + + private final boolean fLazyMode; + DelayedStackRefreshUpdateTester(boolean lazyMode) { + fLazyMode= lazyMode; + } + public int getUpdateFlags(Object viewerInput, TreePath path) { + if (fLazyMode) { + Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : viewerInput; + if (element instanceof IDMVMContext) { + IDMContext dmc= ((IDMVMContext) element).getDMContext(); + if (dmc instanceof IFrameDMContext) { + if (((IFrameDMContext) dmc).getLevel() > 0) { + // mark as dirty only + return DIRTY; + } else { + return FLUSH; + } + } else if (dmc instanceof IExecutionDMContext) { + return DIRTY; + } + } + } + return FLUSH; + } + + public boolean includes(IElementUpdateTester tester) { + // A non-lazy tester includes a lazy tester, but not vice versa. + // This allows entries that were marked as dirty by a flush with + // the lazy mode to be superceded by a non-lazy update which + // actually clears the entries that were marked as dirty. + if (tester instanceof DelayedStackRefreshUpdateTester) { + DelayedStackRefreshUpdateTester sfTester = (DelayedStackRefreshUpdateTester)tester; + if (fLazyMode) { + return sfTester.fLazyMode; + } else { + return false; + } + } + return false; + } + } + + public static String DELAYED_UPDATE_POLICY_ID= "org.eclipse.dd.dsf.ui.viewmodel.update.lazyUpdatePolicy"; //$NON-NLS-1$ + + private static final DelayedStackRefreshUpdateTester fgLazyUpdateTester= new DelayedStackRefreshUpdateTester(true); + private static final DelayedStackRefreshUpdateTester fgNonLazyUpdateTester= new DelayedStackRefreshUpdateTester(false); + + @Override + public IElementUpdateTester getElementUpdateTester(Object event) { + if (event instanceof ISuspendedDMEvent) { + return fgLazyUpdateTester; + } else if (event instanceof FullStackRefreshEvent) { + return fgNonLazyUpdateTester; + } else { + return super.getElementUpdateTester(event); + } + } + + /* + * @see org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy#getID() + */ + @Override + public String getID() { + return DELAYED_UPDATE_POLICY_ID; + } + + /* + * @see org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy#getName() + */ + @Override + public String getName() { + return "Delayed Stack Refresh"; //$NON-NLS-1$ + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/FullStackRefreshEvent.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/FullStackRefreshEvent.java new file mode 100644 index 00000000000..32e567e52b5 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/FullStackRefreshEvent.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. 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.dsf.debug.internal.provisional.ui.viewmodel.launch; + +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; + +/** + * Indicates the end of a sequence of steps. Should be handled like a suspended + * event to trigger a full refresh of stack frames. + */ +public class FullStackRefreshEvent extends AbstractDMEvent { + + public FullStackRefreshEvent(IExecutionDMContext execCtx) { + super(execCtx); + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/StackFramesVMNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/StackFramesVMNode.java index a9dd194b321..f050bf66f60 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/StackFramesVMNode.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/StackFramesVMNode.java @@ -45,7 +45,6 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRe 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.ui.IMemento; @@ -114,6 +113,7 @@ public class StackFramesVMNode extends AbstractDMVMNode } if (update.getOffset() == 0 && update.getLength() == 1) { + // Requesting top stack frame only stackService.getTopFrame( execDmc, new ViewerDataRequestMonitor(getSession().getExecutor(), update) { @@ -128,8 +128,8 @@ public class StackFramesVMNode extends AbstractDMVMNode } }); - // Requesting top stack frame only } else { + // full stack dump stackService.getFrames( execDmc, new ViewerDataRequestMonitor(getSession().getExecutor(), update) { @@ -264,21 +264,6 @@ public class StackFramesVMNode extends AbstractDMVMNode update.setLabel(label.toString(), 0); } - /* - * (non-Javadoc) - * @see org.eclipse.dd.dsf.ui.viewmodel.AbstractVMNode#handleFailedUpdate(org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate) - */ - @Override - protected void handleFailedUpdate(IViewerUpdate update) { - if (update instanceof ILabelUpdate) { - update.done(); - // Avoid repainting the label if it's not available. This only slows - // down the display. - } else { - super.handleFailedUpdate(update); - } - } - /* * (non-Javadoc) * @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#getContextsForEvent(org.eclipse.dd.dsf.ui.viewmodel.VMDelta, java.lang.Object, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) @@ -318,6 +303,8 @@ public class StackFramesVMNode extends AbstractDMVMNode // label has changed. if (e instanceof ISuspendedDMEvent) { return IModelDelta.CONTENT | IModelDelta.EXPAND | IModelDelta.SELECT; + } else if (e instanceof FullStackRefreshEvent) { + return IModelDelta.CONTENT | IModelDelta.EXPAND; } else if (e instanceof StepQueueManager.ISteppingTimedOutEvent) { return IModelDelta.CONTENT; } else if (e instanceof ModelProxyInstalledEvent) { @@ -341,13 +328,16 @@ public class StackFramesVMNode extends AbstractDMVMNode if (parent.getElement() instanceof IDMVMContext) { IExecutionDMContext threadDmc = null; threadDmc = DMContexts.getAncestorOfType( ((IDMVMContext)parent.getElement()).getDMContext(), IExecutionDMContext.class); - buildDeltaForSuspendedEvent((ISuspendedDMEvent)e, threadDmc, triggeringCtx, parent, nodeOffset, rm); + buildDeltaForSuspendedEvent(threadDmc, triggeringCtx, parent, nodeOffset, rm); } else { rm.done(); } + } else if (e instanceof FullStackRefreshEvent) { + IExecutionDMContext execDmc = ((FullStackRefreshEvent)e).getDMContext(); + buildDeltaForFullStackRefreshEvent(execDmc, execDmc, parent, nodeOffset, rm); } else if (e instanceof ISuspendedDMEvent) { IExecutionDMContext execDmc = ((ISuspendedDMEvent)e).getDMContext(); - buildDeltaForSuspendedEvent((ISuspendedDMEvent)e, execDmc, execDmc, parent, nodeOffset, rm); + buildDeltaForSuspendedEvent(execDmc, execDmc, parent, nodeOffset, rm); } else if (e instanceof StepQueueManager.ISteppingTimedOutEvent) { buildDeltaForSteppingTimedOutEvent((StepQueueManager.ISteppingTimedOutEvent)e, parent, nodeOffset, rm); } else if (e instanceof ModelProxyInstalledEvent) { @@ -357,7 +347,55 @@ public class StackFramesVMNode extends AbstractDMVMNode } } - private void buildDeltaForSuspendedEvent(final ISuspendedDMEvent e, final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + private void buildDeltaForSuspendedEvent(final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + IRunControl runControlService = getServicesTracker().getService(IRunControl.class); + IStack stackService = getServicesTracker().getService(IStack.class); + if (stackService == null || runControlService == null) { + // Required services have not initialized yet. Ignore the event. + rm.done(); + return; + } + + // Check if we are building a delta for the thread that triggered the event. + // Only then expand the stack frames and select the top one. + if (executionCtx.equals(triggeringCtx)) { + // Always expand the thread node to show the stack frames. + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND); + + // Retrieve the list of stack frames, and mark the top frame to be selected. + getVMProvider().updateNode( + this, + new VMChildrenUpdate( + parentDelta, getVMProvider().getPresentationContext(), 0, 2, + new DataRequestMonitor>(getExecutor(), rm) { + @Override + public void handleCompleted() { + final List data= getData(); + if (data != null && data.size() != 0) { + parentDelta.addNode(data.get(0), 0, IModelDelta.SELECT | IModelDelta.STATE); + + // Refresh the whole list of stack frames unless the target is already stepping the next command. In + // which case, the refresh will occur when the stepping sequence slows down or stops. Trying to + // refresh the whole stack trace with every step would slow down stepping too much. + IRunControl runControlService = getServicesTracker().getService(IRunControl.class); + if (runControlService != null && + triggeringCtx != null && runControlService.isStepping(triggeringCtx) && + data.size() >= 2) + { + parentDelta.addNode( data.get(1), 1, IModelDelta.STATE); + } + } + // Even in case of errors, complete the request monitor. + rm.done(); + } + }) + ); + } else { + rm.done(); + } + } + + private void buildDeltaForFullStackRefreshEvent(final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { IRunControl runControlService = getServicesTracker().getService(IRunControl.class); IStack stackService = getServicesTracker().getService(IStack.class); if (stackService == null || runControlService == null) { @@ -373,38 +411,9 @@ public class StackFramesVMNode extends AbstractDMVMNode parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); } - // Check if we are building a delta for the thread that triggered the event. - // Only then expand the stack frames and select the top one. - if (executionCtx.equals(triggeringCtx)) { - // Always expand the thread node to show the stack frames. - parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND); - - // Retrieve the list of stack frames, and mark the top frame to be selected. - getVMProvider().updateNode( - this, - new VMChildrenUpdate( - parentDelta, getVMProvider().getPresentationContext(), -1, -1, - new DataRequestMonitor>(getExecutor(), rm) { - @Override - public void handleCompleted() { - if (isSuccess() && getData().size() != 0) { - parentDelta.addNode( getData().get(0), 0, IModelDelta.SELECT | IModelDelta.STATE); - // If second frame is available repaint it, so that a "..." appears. This gives a better - // impression that the frames are not up-to date. - if (getData().size() >= 2) { - parentDelta.addNode( getData().get(1), 1, IModelDelta.STATE); - } - } - // Even in case of errors, complete the request monitor. - rm.done(); - } - }) - ); - } else { - rm.done(); - } - } - + rm.done(); + } + private void buildDeltaForSteppingTimedOutEvent(final StepQueueManager.ISteppingTimedOutEvent e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { // Repaint the stack frame images to have the running symbol. //parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMProvider.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMProvider.java index 523b75dc42e..06f279057dc 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMProvider.java @@ -394,6 +394,7 @@ abstract public class AbstractVMProvider implements IVMProvider public void dispose() { clearNodes(); fRootNode = null; + fDisposed = true; } public void update(final IHasChildrenUpdate[] updates) { diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java index 71651060924..8c56cf5e1b8 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.concurrent.Executor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DsfRunnable; @@ -286,14 +287,10 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa public void refresh() { IElementUpdateTester elementTester = getActiveUpdatePolicy().getElementUpdateTester(ManualUpdatePolicy.REFRESH_EVENT); - List flushKeys = new LinkedList(); - for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) { - flushKeys.add(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester)); + flush(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester)); } - flush(flushKeys); - for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) { if (!proxyStrategy.isDisposed()) { proxyStrategy.fireModelChanged(new ModelDelta(proxyStrategy.getRootElement(), IModelDelta.CONTENT)); @@ -492,97 +489,84 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa * parameter is null, then all entries are flushed. * @param archive */ - private void flush(List flushKeys) { - // To flush the cache data for given context, we have to iterate through all the contexts - // in cache. For each entry that has the given context as a parent, perform the flush. - List flushKeysCopy = new ArrayList(flushKeys.size()); - flushKeysCopy.addAll(flushKeys); - - // Iterate through the cache entries backwards. This means that we will be + private void flush(FlushMarkerKey flushKey) { + // For each entry that has the given context as a parent, perform the flush. + // Iterate through the cache entries backwards. This means that we will be // iterating in order of most-recently-used to least-recently-used. Entry entry = fCacheListHead.fPrevious; - while (entry != fCacheListHead && flushKeysCopy.size() != 0) { - for (Iterator flushKeyItr = flushKeysCopy.iterator(); flushKeyItr.hasNext();) { - FlushMarkerKey flushKey = flushKeyItr.next(); - - if (entry.fKey instanceof FlushMarkerKey) { - FlushMarkerKey entryFlushKey = (FlushMarkerKey)entry.fKey; - // If the context currently being flushed includes the flush - // context in current entry, remove the current entry since it will - // be replaced with one at the end of the list. - // Use special handling for null contexts, which we treat like it's an - // ancestor of all other contexts. - if (flushKey.includes(entryFlushKey)) { - fCacheData.remove(entryFlushKey); - entry.remove(); - } - - // If the flush context in current entry includes the current context - // being flushed, we can stop iterating through the cache entries - // now. - if (entryFlushKey.includes(flushKey)) { - flushKeyItr.remove(); - } + while (entry != fCacheListHead) { + if (entry.fKey instanceof FlushMarkerKey) { + FlushMarkerKey entryFlushKey = (FlushMarkerKey)entry.fKey; + // If the context currently being flushed includes the flush + // context in current entry, remove the current entry since it will + // be replaced with one at the end of the list. + // Use special handling for null contexts, which we treat like it's an + // ancestor of all other contexts. + if (flushKey.includes(entryFlushKey)) { + fCacheData.remove(entryFlushKey); + entry.remove(); } - else if (entry instanceof ElementDataEntry) { - ElementDataEntry elementDataEntry = (ElementDataEntry)entry; - int updateFlags = flushKey.getUpdateFlags((ElementDataKey)elementDataEntry.fKey); - if ((updateFlags & IVMUpdatePolicy.FLUSH) != 0) { - if ((updateFlags & IVMUpdatePolicy.ARCHIVE) != 0) { - // We are saving current data for change history, check if the data is valid. - // If it valid, save it for archive, if it's not valid old archive data will be used - // if there is any. And if there is no old archive data, just remove the cache entry. - for (Iterator> itr = elementDataEntry.fDataOrStatus.entrySet().iterator(); - itr.hasNext();) - { - Map.Entry dataOrStatusEntry = itr.next(); - if (dataOrStatusEntry.getValue() instanceof IDMData) { - elementDataEntry.fArchiveData.put(dataOrStatusEntry.getKey(), (IDMData)dataOrStatusEntry.getValue()); - } - } - elementDataEntry.fDataOrStatus.clear(); - if (elementDataEntry.fArchiveData.isEmpty()) { - fCacheData.remove(entry.fKey); - entry.remove(); - } - } else { - // We are not changing the archived data. If archive data exists in the entry, leave it. - // Otherwise remove the whole entry. - if (!elementDataEntry.fArchiveData.isEmpty()) { - elementDataEntry.fDataOrStatus.clear(); - } else { - fCacheData.remove(entry.fKey); - entry.remove(); + + // If the flush context in current entry includes the current context + // being flushed, we can stop iterating through the cache entries + // now. + if (entryFlushKey.includes(flushKey)) { + break; + } + } + else if (entry instanceof ElementDataEntry) { + ElementDataEntry elementDataEntry = (ElementDataEntry)entry; + int updateFlags = flushKey.getUpdateFlags((ElementDataKey)elementDataEntry.fKey); + if ((updateFlags & IVMUpdatePolicy.FLUSH) != 0) { + if ((updateFlags & IVMUpdatePolicy.ARCHIVE) == IVMUpdatePolicy.ARCHIVE) { + // We are saving current data for change history, check if the data is valid. + // If it valid, save it for archive, if it's not valid old archive data will be used + // if there is any. And if there is no old archive data, just remove the cache entry. + for (Iterator> itr = elementDataEntry.fDataOrStatus.entrySet().iterator(); + itr.hasNext();) + { + Map.Entry dataOrStatusEntry = itr.next(); + if (dataOrStatusEntry.getValue() instanceof IDMData) { + elementDataEntry.fArchiveData.put(dataOrStatusEntry.getKey(), (IDMData)dataOrStatusEntry.getValue()); } } - elementDataEntry.fHasChildren = null; - elementDataEntry.fChildrenCount = null; - elementDataEntry.fChildren = null; - } else if ((updateFlags & IVMUpdatePolicy.DIRTY) != 0) { - elementDataEntry.fDirty = true; + elementDataEntry.fDataOrStatus.clear(); + if (elementDataEntry.fArchiveData.isEmpty()) { + fCacheData.remove(entry.fKey); + entry.remove(); + } + } else { + // We are not changing the archived data. If archive data exists in the entry, leave it. + // Otherwise remove the whole entry. + if (!elementDataEntry.fArchiveData.isEmpty()) { + elementDataEntry.fDataOrStatus.clear(); + } else { + fCacheData.remove(entry.fKey); + entry.remove(); + } } + elementDataEntry.fHasChildren = null; + elementDataEntry.fChildrenCount = null; + elementDataEntry.fChildren = null; + elementDataEntry.fDirty = false; + } else if ((updateFlags & IVMUpdatePolicy.DIRTY) != 0) { + elementDataEntry.fDirty = true; } } entry = entry.fPrevious; } - for (FlushMarkerKey flushKey : flushKeys) { - // Insert a marker for this flush operation. - Entry flushMarkerEntry = new Entry(flushKey); - fCacheData.put(flushKey, flushMarkerEntry); - flushMarkerEntry.insert(fCacheListHead); - } + // Insert a marker for this flush operation. + Entry flushMarkerEntry = new Entry(flushKey); + fCacheData.put(flushKey, flushMarkerEntry); + flushMarkerEntry.insert(fCacheListHead); } @Override protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) { IElementUpdateTester elementTester = getActiveUpdatePolicy().getElementUpdateTester(event); - List flushKeys = new LinkedList(); - - flushKeys.add(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester)); - - flush(flushKeys); + flush(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester)); super.handleEvent(proxyStrategy, event, rm); } @@ -650,7 +634,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa } } - return new ElementDataKey(rootElement, node, update.getElement(), update.getElementPath()); + return new ElementDataKey(rootElement, node, update.getViewerInput(), update.getElementPath()); } /** @@ -671,7 +655,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa entry.insert(fCacheListHead); } - // Update they root element marker: + // Update the root element marker: // - ensure that the root marker is root markers' map, // - ensure that the root marker is in the cache map, // - and ensure that it's at the end of the cache. @@ -719,33 +703,38 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa ElementDataKey key = makeEntryKey(node, update); final ElementDataEntry entry = getElementDataEntry(key); - Object dataOrStatus = entry.fDataOrStatus.get(dmc); - if(dataOrStatus != null) { - if (dataOrStatus instanceof IDMData) { - rm.setData( (IDMData)dataOrStatus ); - } else { - rm.setStatus((IStatus)dataOrStatus ); - } + if (entry.fDirty) { + rm.setStatus(Status.CANCEL_STATUS); rm.done(); } else { - service.getExecutor().execute(new DsfRunnable() { - public void run() { - service.getModelData(dmc, - new ViewerDataRequestMonitor(executor, update) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - entry.fDataOrStatus.put(dmc, getData()); - rm.setData(getData()); - } else { - entry.fDataOrStatus.put(dmc, getStatus()); - rm.setStatus(getStatus()); - } - rm.done(); - } - }); - } - }); + Object dataOrStatus = entry.fDataOrStatus.get(dmc); + if(dataOrStatus != null) { + if (dataOrStatus instanceof IDMData) { + rm.setData( dataOrStatus ); + } else { + rm.setStatus((IStatus)dataOrStatus ); + } + rm.done(); + } else { + service.getExecutor().execute(new DsfRunnable() { + public void run() { + service.getModelData(dmc, + new ViewerDataRequestMonitor(executor, update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + entry.fDataOrStatus.put(dmc, getData()); + rm.setData(getData()); + } else { + entry.fDataOrStatus.put(dmc, getStatus()); + rm.setStatus(getStatus()); + } + rm.done(); + } + }); + } + }); + } } } }); diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java index e10eb93caf8..5feeaef3506 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java @@ -11,22 +11,34 @@ *******************************************************************************/ package org.eclipse.dd.gdb.internal.ui.viewmodel.launch; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.concurrent.ThreadSafe; import org.eclipse.dd.dsf.datamodel.DMContexts; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMEvent; +import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.DelayedStackRefreshUpdatePolicy; +import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.FullStackRefreshEvent; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StackFramesVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StandardProcessVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; +import org.eclipse.dd.dsf.ui.viewmodel.IVMModelProxy; import org.eclipse.dd.dsf.ui.viewmodel.IVMNode; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.GDBExitedEvent; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.GDBStartedEvent; import org.eclipse.dd.mi.service.command.MIInferiorProcess.InferiorExitedDMEvent; @@ -46,8 +58,15 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont public class LaunchVMProvider extends AbstractDMVMProvider implements IDebugEventSetListener, ILaunchesListener2 { - @ThreadSafe - public LaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) + /** + * Delay (in milliseconds) before a full stack trace will be requested. + */ + private static final int FRAME_UPDATE_DELAY= 200; + + private final Map> fRefreshStackFramesFutures = new HashMap>(); + + @ThreadSafe + public LaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) { super(adapter, presentationContext, session); @@ -70,6 +89,10 @@ public class LaunchVMProvider extends AbstractDMVMProvider DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); } + @Override + protected IVMUpdatePolicy[] createUpdateModes() { + return new IVMUpdatePolicy[] { new DelayedStackRefreshUpdatePolicy() }; + } public void handleDebugEvents(final DebugEvent[] events) { if (isDisposed()) return; @@ -91,6 +114,61 @@ public class LaunchVMProvider extends AbstractDMVMProvider } } + @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);