mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
[202553] - [debug view][stack] Stack frames layout node retrieves all stack frames when stepping fast.
This commit is contained in:
parent
76b3eddc76
commit
152ee1c3f1
8 changed files with 393 additions and 165 deletions
|
@ -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);
|
||||
|
|
|
@ -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) )
|
||||
{
|
||||
|
|
|
@ -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$
|
||||
}
|
||||
|
||||
}
|
|
@ -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<IExecutionDMContext> {
|
||||
|
||||
public FullStackRefreshEvent(IExecutionDMContext execCtx) {
|
||||
super(execCtx);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<IFrameDMContext>(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<IFrameDMContext[]>(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<List<Object>>(getExecutor(), rm) {
|
||||
@Override
|
||||
public void handleCompleted() {
|
||||
final List<Object> 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<List<Object>>(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);
|
||||
|
|
|
@ -394,6 +394,7 @@ abstract public class AbstractVMProvider implements IVMProvider
|
|||
public void dispose() {
|
||||
clearNodes();
|
||||
fRootNode = null;
|
||||
fDisposed = true;
|
||||
}
|
||||
|
||||
public void update(final IHasChildrenUpdate[] updates) {
|
||||
|
|
|
@ -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<FlushMarkerKey> flushKeys = new LinkedList<FlushMarkerKey>();
|
||||
|
||||
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<FlushMarkerKey> 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<FlushMarkerKey> flushKeysCopy = new ArrayList<FlushMarkerKey>(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<FlushMarkerKey> 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<Map.Entry<IDMContext, Object>> itr = elementDataEntry.fDataOrStatus.entrySet().iterator();
|
||||
itr.hasNext();)
|
||||
{
|
||||
Map.Entry<IDMContext, Object> 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<Map.Entry<IDMContext, Object>> itr = elementDataEntry.fDataOrStatus.entrySet().iterator();
|
||||
itr.hasNext();)
|
||||
{
|
||||
Map.Entry<IDMContext, Object> 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<FlushMarkerKey> flushKeys = new LinkedList<FlushMarkerKey>();
|
||||
|
||||
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<IDMData>(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<IDMData>(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();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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<IExecutionDMContext,ScheduledFuture<?>> fRefreshStackFramesFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
|
||||
|
||||
@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);
|
||||
|
|
Loading…
Add table
Reference in a new issue