1
0
Fork 0
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:
Pawel Piech 2008-06-03 04:56:22 +00:00
parent 76b3eddc76
commit 152ee1c3f1
8 changed files with 393 additions and 165 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -394,6 +394,7 @@ abstract public class AbstractVMProvider implements IVMProvider
public void dispose() {
clearNodes();
fRootNode = null;
fDisposed = true;
}
public void update(final IHasChildrenUpdate[] updates) {

View file

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

View file

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