mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
[205142] Refactored use of DM contexts to make them more flexible.
This commit is contained in:
parent
18fd2d6ef6
commit
1d31b66b19
10 changed files with 586 additions and 271 deletions
|
@ -15,7 +15,6 @@ import org.eclipse.core.runtime.Status;
|
||||||
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
|
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
|
||||||
import org.eclipse.dd.dsf.concurrent.Immutable;
|
import org.eclipse.dd.dsf.concurrent.Immutable;
|
||||||
import org.eclipse.dd.dsf.datamodel.DMContexts;
|
import org.eclipse.dd.dsf.datamodel.DMContexts;
|
||||||
import org.eclipse.dd.dsf.debug.service.INativeProcesses;
|
|
||||||
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
import org.eclipse.dd.dsf.debug.service.IRunControl;
|
||||||
import org.eclipse.dd.dsf.debug.service.IStepQueueManager;
|
import org.eclipse.dd.dsf.debug.service.IStepQueueManager;
|
||||||
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
|
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
|
||||||
|
@ -40,10 +39,6 @@ public abstract class DsfCommandRunnable extends DsfRunnable {
|
||||||
return fTracker.getService(IStepQueueManager.class);
|
return fTracker.getService(IStepQueueManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public INativeProcesses getProcesses() {
|
|
||||||
return fTracker.getService(INativeProcesses.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DsfCommandRunnable(DsfServicesTracker servicesTracker, Object element, IDebugCommandRequest request) {
|
public DsfCommandRunnable(DsfServicesTracker servicesTracker, Object element, IDebugCommandRequest request) {
|
||||||
fTracker = servicesTracker;
|
fTracker = servicesTracker;
|
||||||
if (element instanceof DMVMContext) {
|
if (element instanceof DMVMContext) {
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2006 Wind River Systems and others.
|
|
||||||
* All rights reserved. This program and the accompanying materials
|
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
|
||||||
* which accompanies this distribution, and is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Wind River Systems - initial API and implementation
|
|
||||||
*******************************************************************************/
|
|
||||||
package org.eclipse.dd.dsf.debug.ui.actions;
|
|
||||||
|
|
||||||
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
|
||||||
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
|
||||||
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
|
|
||||||
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
|
||||||
import org.eclipse.dd.dsf.datamodel.DMContexts;
|
|
||||||
import org.eclipse.dd.dsf.debug.service.INativeProcesses;
|
|
||||||
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
|
|
||||||
import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin;
|
|
||||||
import org.eclipse.dd.dsf.service.DsfServicesTracker;
|
|
||||||
import org.eclipse.dd.dsf.service.DsfSession;
|
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
|
|
||||||
import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext;
|
|
||||||
import org.eclipse.debug.core.commands.IDebugCommandRequest;
|
|
||||||
import org.eclipse.debug.core.commands.IEnabledStateRequest;
|
|
||||||
import org.eclipse.debug.core.commands.ITerminateHandler;
|
|
||||||
|
|
||||||
public class DsfTerminateCommand implements ITerminateHandler {
|
|
||||||
private final DsfExecutor fExecutor;
|
|
||||||
private final DsfServicesTracker fTracker;
|
|
||||||
|
|
||||||
public DsfTerminateCommand(DsfSession session) {
|
|
||||||
fExecutor = session.getExecutor();
|
|
||||||
fTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), session.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispose() {
|
|
||||||
fTracker.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run control may not be avilable after a connection is terminated and shut down.
|
|
||||||
public void canExecute(final IEnabledStateRequest request) {
|
|
||||||
if (request.getElements().length != 1 ||
|
|
||||||
!(request.getElements()[0] instanceof DMVMContext) )
|
|
||||||
{
|
|
||||||
request.setEnabled(false);
|
|
||||||
request.done();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Javac doesn't like the cast to "(AbstractDMVMLayoutNode<?>.DMVMContext)" need to use the
|
|
||||||
// construct below and suppress warnings.
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
AbstractDMVMLayoutNode.DMVMContext vmc = (AbstractDMVMLayoutNode.DMVMContext)request.getElements()[0];
|
|
||||||
final IExecutionDMContext dmc = DMContexts.getAncestorOfType(vmc.getDMC(), IExecutionDMContext.class);
|
|
||||||
if (dmc == null) {
|
|
||||||
request.setEnabled(false);
|
|
||||||
request.done();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fExecutor.execute(
|
|
||||||
new DsfRunnable() {
|
|
||||||
public void run() {
|
|
||||||
// Get the processes service and the exec context.
|
|
||||||
INativeProcesses processes = fTracker.getService(INativeProcesses.class);
|
|
||||||
if (processes == null || dmc == null) {
|
|
||||||
// Context or service already invalid.
|
|
||||||
request.done();
|
|
||||||
} else {
|
|
||||||
// Check the teriminate.
|
|
||||||
processes.canTerminate(
|
|
||||||
processes.getProcessForDebugContext(dmc),
|
|
||||||
new DataRequestMonitor<Boolean>(fExecutor, null) {
|
|
||||||
@Override
|
|
||||||
public void handleCompleted() {
|
|
||||||
request.setEnabled(getData());
|
|
||||||
request.done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean execute(final IDebugCommandRequest request) {
|
|
||||||
if (request.getElements().length != 1) {
|
|
||||||
request.done();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
|
|
||||||
@Override public void doExecute() {
|
|
||||||
getProcesses().terminate(
|
|
||||||
getProcesses().getProcessForDebugContext(getContext()), new RequestMonitor(fExecutor, null));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -33,6 +33,7 @@ import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext;
|
||||||
import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMData;
|
import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMData;
|
||||||
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
|
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
|
||||||
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData;
|
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData;
|
||||||
|
import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryDMContext;
|
||||||
import org.eclipse.dd.dsf.service.DsfSession;
|
import org.eclipse.dd.dsf.service.DsfSession;
|
||||||
import org.eclipse.dd.dsf.service.IDsfService;
|
import org.eclipse.dd.dsf.service.IDsfService;
|
||||||
import org.eclipse.debug.core.DebugException;
|
import org.eclipse.debug.core.DebugException;
|
||||||
|
@ -66,7 +67,7 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl
|
||||||
private final String fModelId;
|
private final String fModelId;
|
||||||
private final DsfSession fSession;
|
private final DsfSession fSession;
|
||||||
private final DsfExecutor fExecutor;
|
private final DsfExecutor fExecutor;
|
||||||
private IDMContext fContext;
|
private IMemoryDMContext fContext;
|
||||||
private final ServiceTracker fMemoryServiceTracker;
|
private final ServiceTracker fMemoryServiceTracker;
|
||||||
private final ServiceTracker fExpressionServiceTracker;
|
private final ServiceTracker fExpressionServiceTracker;
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl
|
||||||
* @param dmc
|
* @param dmc
|
||||||
* @throws DebugException
|
* @throws DebugException
|
||||||
*/
|
*/
|
||||||
public DsfMemoryBlockRetrieval(String modelId, IDMContext dmc) throws DebugException {
|
public DsfMemoryBlockRetrieval(String modelId, IMemoryDMContext dmc) throws DebugException {
|
||||||
|
|
||||||
fModelId = modelId;
|
fModelId = modelId;
|
||||||
fContext = dmc;
|
fContext = dmc;
|
||||||
|
@ -263,11 +264,8 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the DMC
|
|
||||||
fContext = dmc;
|
|
||||||
|
|
||||||
// Resolve the expression
|
// Resolve the expression
|
||||||
blockAddress = resolveMemoryAddress(fContext, expression);
|
blockAddress = resolveMemoryAddress(dmc, expression);
|
||||||
if (blockAddress == null) {
|
if (blockAddress == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,9 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.dd.dsf.debug.service;
|
package org.eclipse.dd.dsf.debug.service;
|
||||||
|
|
||||||
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMData;
|
import org.eclipse.dd.dsf.service.IDsfService;
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMEvent;
|
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMService;
|
|
||||||
import org.eclipse.debug.core.model.IBreakpoint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Breakpoint service interface. The breakpoint service tracks platform breakpoint
|
* Breakpoint service interface. The breakpoint service tracks platform breakpoint
|
||||||
|
@ -24,26 +21,28 @@ import org.eclipse.debug.core.model.IBreakpoint;
|
||||||
* breakpoint status in more detail and more dynamically than it it possible with
|
* breakpoint status in more detail and more dynamically than it it possible with
|
||||||
* just the marker-based breakpoint object.
|
* just the marker-based breakpoint object.
|
||||||
*/
|
*/
|
||||||
public interface IBreakpoints extends IDMService {
|
public interface IBreakpoints extends IDsfService {
|
||||||
|
|
||||||
public enum BreakpointStatus { INSTALLED, FAILED_TO_INSTALL, FILTERED_OUT }
|
/**
|
||||||
|
* Marker interface for a context for which breakpoints can be installed.
|
||||||
|
*/
|
||||||
|
public interface IBreakpointsDMContext extends IDMContext {};
|
||||||
|
|
||||||
public interface IBreakpointDMContext extends IDMContext {}
|
/**
|
||||||
|
* Install and begin tracking breakpoints for given context. The service
|
||||||
|
* will keep installing new breakpoints that appear in the IDE for this
|
||||||
|
* context until {@link #uninstallBreakpoints(IDMContext)} is called for that
|
||||||
|
* context.
|
||||||
|
* @param dmc Context to start tracking breakpoints for.
|
||||||
|
* @param rm Completion callback.
|
||||||
|
*/
|
||||||
|
public void installBreakpoints(IDMContext dmc, RequestMonitor rm);
|
||||||
|
|
||||||
public interface IBreakpointDMData extends IDMData {
|
/**
|
||||||
IBreakpoint getPlatformBreakpoint();
|
* Uninstall and stop tracking breakpoints for the given context.
|
||||||
BreakpointStatus getStatus();
|
* @param dmc Context to start tracking breakpoints for.
|
||||||
}
|
* @param rm Completion callback.
|
||||||
|
*/
|
||||||
public interface IBreakpointDMEvent extends IDMEvent<IBreakpointDMContext> {}
|
public void uninstallBreakpoints(IDMContext dmc, RequestMonitor rm);
|
||||||
|
|
||||||
public interface IBreakpointInstalledDMEvent extends IBreakpointDMEvent {}
|
|
||||||
public interface IBreakpointUninstalledDMEvent extends IBreakpointDMEvent {}
|
|
||||||
public interface IBreakpointInstallFailedDMEvent extends IBreakpointDMEvent {}
|
|
||||||
|
|
||||||
public interface IBreakpointHitEvent extends IBreakpointDMEvent {}
|
|
||||||
|
|
||||||
public void getAllBreakpoints(IDMContext ctx, DataRequestMonitor<IBreakpointDMContext[]> rm);
|
|
||||||
public void getBreakpoints(IDMContext ctx, IBreakpoint platformBp, DataRequestMonitor<IBreakpointDMContext[]> rm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ import org.eclipse.debug.core.model.MemoryByte;
|
||||||
*/
|
*/
|
||||||
public interface IMemory extends IDsfService {
|
public interface IMemory extends IDsfService {
|
||||||
|
|
||||||
|
public interface IMemoryDMContext extends IDMContext {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event generated every time a range of bytes is modified.
|
* Event generated every time a range of bytes is modified.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2006 Wind River Systems and others.
|
|
||||||
* All rights reserved. This program and the accompanying materials
|
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
|
||||||
* which accompanies this distribution, and is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Wind River Systems - initial API and implementation
|
|
||||||
*******************************************************************************/
|
|
||||||
package org.eclipse.dd.dsf.debug.service;
|
|
||||||
|
|
||||||
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
|
||||||
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMData;
|
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMEvent;
|
|
||||||
import org.eclipse.dd.dsf.datamodel.IDMService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This interface provides access to the native OS's process
|
|
||||||
* information, manipulation methods, and debugging methods.
|
|
||||||
* This service provides a relatively simple interface for
|
|
||||||
* manipulating processes as compared with a full-blown
|
|
||||||
* remote target debugger.
|
|
||||||
*/
|
|
||||||
public interface INativeProcesses extends IDMService {
|
|
||||||
|
|
||||||
public interface IThreadDMContext extends IDMContext {}
|
|
||||||
public interface IProcessDMContext extends IDMContext {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for thread and process object data.
|
|
||||||
*/
|
|
||||||
public interface IThreadDMData extends IDMData {
|
|
||||||
String getName();
|
|
||||||
String getId();
|
|
||||||
boolean isDebuggerAttached();
|
|
||||||
IDMContext getDebugContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for thread and process object data.
|
|
||||||
*/
|
|
||||||
public interface IProcessDMData extends IDMData {
|
|
||||||
String getName();
|
|
||||||
String getId();
|
|
||||||
boolean isDebuggerAttached();
|
|
||||||
IDMContext getDebugContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event indicating that process data has changed.
|
|
||||||
*/
|
|
||||||
public interface IProcessChangedDMEvent extends IDMEvent<IProcessDMContext> {}
|
|
||||||
|
|
||||||
|
|
||||||
public interface IProcessStartedEvent extends IDMEvent<IDMContext> {
|
|
||||||
IProcessDMContext getProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IProcessExitedEvent extends IDMEvent<IDMContext> {
|
|
||||||
IProcessDMContext getProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getThreadData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm);
|
|
||||||
|
|
||||||
public void getProcessData(IProcessDMContext dmc, DataRequestMonitor<IProcessDMData> rm);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a thread for the corresponding context. <code>null</code> if no corresponding
|
|
||||||
* thread exists.
|
|
||||||
* @param execCtx
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public IThreadDMContext getThreadForDebugContext(IDMContext execCtx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a process context corresponding to the given context. <code>null</code> if no
|
|
||||||
* corresponding process exists.
|
|
||||||
*/
|
|
||||||
public IProcessDMContext getProcessForDebugContext(IDMContext execCtx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the current list of processes running on target.
|
|
||||||
* @param rm Request completion monitor, to be filled in with array of process contexts.
|
|
||||||
*/
|
|
||||||
void getRunningProcesses(DataRequestMonitor<IProcessDMContext[]> rm);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attaches debugger to the given process.
|
|
||||||
*/
|
|
||||||
void attachDebuggerToProcess(IProcessDMContext procCtx, RequestMonitor requestMonitor);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a new process.
|
|
||||||
* @param file Process image to use for the new process.
|
|
||||||
* @param rm Request completion monitor, to be filled in with the process context.
|
|
||||||
*/
|
|
||||||
void runNewProcess(String file, DataRequestMonitor<IProcessDMContext> rm);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a new process with debugger attached.
|
|
||||||
* @param file Process image to use for the new process.
|
|
||||||
* @param rm Request completion monitor, to be willed in with the process context.
|
|
||||||
*/
|
|
||||||
void debugNewProcess(String file, DataRequestMonitor<IProcessDMContext> rm);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the list of processes which are currently under
|
|
||||||
* debugger control.
|
|
||||||
* @param rm Request completion monitor.
|
|
||||||
*/
|
|
||||||
void getProcessesBeingDebugged(DataRequestMonitor<IProcessDMContext[]> rm);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the given process or thread can be terminated.
|
|
||||||
* @param thread Thread or process to terminate.
|
|
||||||
* @param rm Return token.
|
|
||||||
*/
|
|
||||||
void canTerminate(IDMContext ctx, DataRequestMonitor<Boolean> rm);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Terminates the selected process or thread.
|
|
||||||
* @param thread Thread or process to terminate.
|
|
||||||
* @param rm Request completion monitor, indicates success or failure.
|
|
||||||
*/
|
|
||||||
void terminate(IDMContext ctx, RequestMonitor requestMonitor);
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2007 Wind River Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Wind River Systems - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.dd.dsf.debug.service;
|
||||||
|
|
||||||
|
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
||||||
|
import org.eclipse.dd.dsf.service.IDsfService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ISignals extends IDsfService {
|
||||||
|
/**
|
||||||
|
* Marker interface for a context for which signals can be set.
|
||||||
|
*/
|
||||||
|
public interface ISignalsDMContext extends IDMContext {};
|
||||||
|
|
||||||
|
}
|
|
@ -104,10 +104,12 @@ public interface IStack extends IDMService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the stack depth of the specified stack frame.
|
* Retrieves the stack depth of the specified stack frame.
|
||||||
|
* @param dmc Context to retrieve data for.
|
||||||
|
* @param The maximum depth of stack to calculate. Should be 0 to calculate
|
||||||
|
* depth with no limit.
|
||||||
|
* @param rm Callback
|
||||||
*/
|
*/
|
||||||
void getStackDepth(DataRequestMonitor<Integer> rm);
|
void getStackDepth(IDMContext dmc, int maxDepth, DataRequestMonitor<Integer> rm);
|
||||||
|
|
||||||
void getStackDepth(int maxDepth, DataRequestMonitor<Integer> rm);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,518 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2007 Wind River Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Wind River Systems - initial API and implementation
|
||||||
|
* Ericsson - Modified for caching commands corresponding to multiple execution contexts
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
package org.eclipse.dd.dsf.debug.service.command;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.dd.dsf.datamodel.DMContexts;
|
||||||
|
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
||||||
|
import org.eclipse.dd.dsf.debug.DsfDebugPlugin;
|
||||||
|
import org.eclipse.dd.dsf.service.IDsfService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a utility class for caching results of MI Commands. Return MIInfo
|
||||||
|
* data is retrieved from the cache if command was previously executed, and
|
||||||
|
* it is executed with MICommand service if it was not previously seen.
|
||||||
|
*
|
||||||
|
* Resetting the cache has to be performed by the object owning the cache when
|
||||||
|
* when an event indicates that the data is obsolete (which is specific to the
|
||||||
|
* types of commands being cached).
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CommandCache implements ICommandListener
|
||||||
|
{
|
||||||
|
static enum CommandStyle { COALESCED, NONCOALESCED }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds cache information for a given command.
|
||||||
|
* @param <V> Type matches the result type associated with the command.
|
||||||
|
*/
|
||||||
|
class CommandInfo {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Control variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** List of the request monitors associated with this command */
|
||||||
|
List<DataRequestMonitor<ICommandResult>> fCurrentRequestMonitors ;
|
||||||
|
|
||||||
|
/** Original command. Need for reference from Queue completion notification */
|
||||||
|
ICommand<ICommandResult> fCommand;
|
||||||
|
|
||||||
|
/** Style of this command ( internal coalesced or not) */
|
||||||
|
CommandStyle fCmdStyle;
|
||||||
|
|
||||||
|
/** Command being processed for this command */
|
||||||
|
CommandInfo fCoalescedCmd;
|
||||||
|
|
||||||
|
/** No longer really used and needs to be deleted */
|
||||||
|
int fResetCounterStatus;
|
||||||
|
|
||||||
|
public CommandInfo( CommandStyle cmdstyle, ICommand<ICommandResult> cmd, DataRequestMonitor<ICommandResult> rm ) {
|
||||||
|
|
||||||
|
fCmdStyle = cmdstyle;
|
||||||
|
fCommand = cmd;
|
||||||
|
fCurrentRequestMonitors = new LinkedList<DataRequestMonitor<ICommandResult>>();
|
||||||
|
fCurrentRequestMonitors.add(rm);
|
||||||
|
fCoalescedCmd = null;
|
||||||
|
fResetCounterStatus = fResetCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandStyle getCommandstyle() { return fCmdStyle; }
|
||||||
|
public List<DataRequestMonitor<ICommandResult>> getRequestMonitorList() { return fCurrentRequestMonitors; }
|
||||||
|
public ICommand<ICommandResult> getCommand() { return fCommand; }
|
||||||
|
public CommandInfo getCoalescedCmd() { return fCoalescedCmd; }
|
||||||
|
public void setCoalescedCmd( CommandInfo cmd ) { fCoalescedCmd = cmd; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (!(other instanceof CommandInfo)) return false;
|
||||||
|
CommandInfo otherCmd = (CommandInfo)other;
|
||||||
|
|
||||||
|
return otherCmd.fCommand.equals(fCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (fCommand.hashCode()+ (fResetCounterStatus + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This class contains 5 significant lists.
|
||||||
|
*
|
||||||
|
* Cached Results :
|
||||||
|
*
|
||||||
|
* Contains a mapping of commands and their completed results. Until the cached
|
||||||
|
* results are cleared by the owner of the cache.
|
||||||
|
*
|
||||||
|
* Pending Commands Not Queued :
|
||||||
|
*
|
||||||
|
* The Control object has not yet indicated that it has recognized the command
|
||||||
|
* yet. The user is not allowed to interrogate these objects until the Control
|
||||||
|
* object indicates they have been queued ( commandQueued notification ).
|
||||||
|
*
|
||||||
|
* Pending Commands Unsent :
|
||||||
|
*
|
||||||
|
* This is the list of commands which have been issued to the Control object but
|
||||||
|
* have not been actually issued to the backend. These commands represent coalesce
|
||||||
|
* options. They may be compared against the Queued list being maintained by the
|
||||||
|
* Control object until told otherwise - commandSent notification ).
|
||||||
|
*
|
||||||
|
* Pending Commands Sent :
|
||||||
|
*
|
||||||
|
* This is a list of commands which have been issued to the Control object and
|
||||||
|
* have also been sent to the backend. It is not possible use these objects for
|
||||||
|
* coalescents.
|
||||||
|
*
|
||||||
|
* Coalesced Pending Q :
|
||||||
|
*
|
||||||
|
* These represent original commands for which a new coalesced command has been
|
||||||
|
* created. When the coalesced commands completes the results will be decomposed
|
||||||
|
* when back into individual results from this command.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private boolean fIsTargetAvailable = true;
|
||||||
|
private int fResetCounter = 0;
|
||||||
|
|
||||||
|
private ICommandControl fCommandControl;
|
||||||
|
|
||||||
|
private Map<IDMContext, HashMap<CommandInfo, ICommandResult>> fCachedContexts = new HashMap<IDMContext, HashMap<CommandInfo, ICommandResult>>();
|
||||||
|
|
||||||
|
private ArrayList<CommandInfo> fPendingQCommandsSent = new ArrayList<CommandInfo>();
|
||||||
|
|
||||||
|
private ArrayList<CommandInfo> fPendingQCommandsNotYetSent = new ArrayList<CommandInfo>();
|
||||||
|
|
||||||
|
private ArrayList<CommandInfo> fPendingQWaitingForCoalescedCompletion = new ArrayList<CommandInfo>();
|
||||||
|
|
||||||
|
public CommandCache(ICommandControl control) {
|
||||||
|
fCommandControl = control;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We listen for the notifications that the commands have been sent to the
|
||||||
|
* backend from the GDB/MI Communications engine.
|
||||||
|
*/
|
||||||
|
fCommandControl.addCommandListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructs a coalesced command if possible.
|
||||||
|
*/
|
||||||
|
private CommandInfo getCoalescedCommand(CommandInfo cmd) {
|
||||||
|
|
||||||
|
for ( CommandInfo currentUnsentEntry : new ArrayList<CommandInfo>(fPendingQCommandsNotYetSent) ) {
|
||||||
|
/*
|
||||||
|
* Get the current unsent entry to determine if we can coalesced with it.
|
||||||
|
*/
|
||||||
|
ICommand<?> unsentCommand = currentUnsentEntry.getCommand();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we can so construct a new COALESCED command from scratch.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// For sanity's sake, cast the generic ?'s to concrete types in the cache implementation.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ICommand<ICommandResult> coalescedCmd =
|
||||||
|
(ICommand<ICommandResult>)unsentCommand.coalesceWith( cmd.getCommand() );
|
||||||
|
|
||||||
|
if ( coalescedCmd != null ) {
|
||||||
|
CommandInfo coalescedCmdInfo = new CommandInfo( CommandStyle.COALESCED, coalescedCmd, null) ;
|
||||||
|
|
||||||
|
if ( currentUnsentEntry.getCommandstyle() == CommandStyle.COALESCED ) {
|
||||||
|
/*
|
||||||
|
* We matched a command which is itself already a COALESCED command. So
|
||||||
|
* we need to run through the reference list and point all the current
|
||||||
|
* command which are referencing the command we just subsumed and change
|
||||||
|
* them to point to the new super command.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for ( CommandInfo waitingEntry : new ArrayList<CommandInfo>(fPendingQWaitingForCoalescedCompletion) ) {
|
||||||
|
|
||||||
|
if ( waitingEntry.getCoalescedCmd() == currentUnsentEntry ) {
|
||||||
|
/*
|
||||||
|
* This referenced the old command change it to point to the new one.
|
||||||
|
*/
|
||||||
|
waitingEntry.setCoalescedCmd(coalescedCmdInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* This currently unsent entry needs to go into the coalescing list. To
|
||||||
|
* be completed when the coalesced command comes back with a result.
|
||||||
|
*/
|
||||||
|
fPendingQWaitingForCoalescedCompletion.add(currentUnsentEntry);
|
||||||
|
currentUnsentEntry.setCoalescedCmd(coalescedCmdInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Either way we want to take the command back from the Control object so it
|
||||||
|
* does not continue to process it.
|
||||||
|
*/
|
||||||
|
fPendingQCommandsNotYetSent.remove(currentUnsentEntry);
|
||||||
|
fCommandControl.removeCommand(unsentCommand);
|
||||||
|
|
||||||
|
return( coalescedCmdInfo );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes given ICommand, or retrieves the cached result if known.
|
||||||
|
* @param command Command to execute.
|
||||||
|
* @param rm Return token, contains the retrieved MIInfo object as
|
||||||
|
* well as its cache status.
|
||||||
|
*/
|
||||||
|
public <V extends ICommandResult> void execute(ICommand<V> command, DataRequestMonitor<V> rm) {
|
||||||
|
assert fCommandControl.getExecutor().isInExecutorThread();
|
||||||
|
|
||||||
|
// Cast the generic ?'s to concrete types in the cache implementation.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final ICommand<ICommandResult> genericCommand = (ICommand<ICommandResult>)command;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final DataRequestMonitor<ICommandResult> genericDone = (DataRequestMonitor<ICommandResult>) rm;
|
||||||
|
|
||||||
|
CommandInfo cachedCmd = new CommandInfo( CommandStyle.NONCOALESCED, genericCommand, genericDone) ;
|
||||||
|
|
||||||
|
final IDMContext context = genericCommand.getContext();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If command is already cached, just return the cached data.
|
||||||
|
*/
|
||||||
|
if(fCachedContexts.get(context) != null && fCachedContexts.get(context).containsKey(cachedCmd)){
|
||||||
|
// Cast to the erased type of the returned command result.
|
||||||
|
// To ensure type safety, we are relying on the correct matching
|
||||||
|
// of command and result in the cached results map.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
V v = (V) fCachedContexts.get(context).get(cachedCmd);
|
||||||
|
|
||||||
|
rm.setData(v);
|
||||||
|
rm.done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return an error if the target is available anymore.
|
||||||
|
*/
|
||||||
|
if (!fIsTargetAvailable) {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, DsfDebugPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Target not available.", null)); //$NON-NLS-1$
|
||||||
|
rm.done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are waiting for this command to complete ( but the command has
|
||||||
|
* been sent to the debug engine), add this request monitor to list of waiting monitors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for ( CommandInfo sentCommand : fPendingQCommandsSent ) {
|
||||||
|
if ( sentCommand.equals( cachedCmd )) {
|
||||||
|
sentCommand.getRequestMonitorList().add(genericDone);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We see if this command can be combined into a coalesced one. The
|
||||||
|
* coalesce routine will take care of the already enqueued one which
|
||||||
|
* this command is being coalesced with.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CommandInfo coalescedCmd = getCoalescedCommand(cachedCmd);
|
||||||
|
|
||||||
|
if ( coalescedCmd != null ) {
|
||||||
|
/*
|
||||||
|
* The original command we were handed needs to go into the waiting QUEUE.
|
||||||
|
* We also need to point it it to the coalesced command.
|
||||||
|
*/
|
||||||
|
fPendingQWaitingForCoalescedCompletion.add(cachedCmd);
|
||||||
|
cachedCmd.setCoalescedCmd(coalescedCmd);
|
||||||
|
cachedCmd = coalescedCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we have a command to send ( coalesced or not ). Put it in the cannot touch
|
||||||
|
* it list and give it to the Control object. Our state handlers will move it into
|
||||||
|
* the proper list as the Control object deals with it.
|
||||||
|
*/
|
||||||
|
final CommandInfo finalCachedCmd = cachedCmd;
|
||||||
|
fPendingQCommandsNotYetSent.add(finalCachedCmd);
|
||||||
|
|
||||||
|
fCommandControl.queueCommand(
|
||||||
|
finalCachedCmd.getCommand(),
|
||||||
|
new DataRequestMonitor<ICommandResult>(fCommandControl.getExecutor(), null) {
|
||||||
|
@Override
|
||||||
|
public void handleCompleted() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match this up with a command set we know about.
|
||||||
|
*/
|
||||||
|
if ( ! fPendingQCommandsSent.remove(finalCachedCmd) ) {
|
||||||
|
/*
|
||||||
|
* It should not be the case that this is possible. It would mean we
|
||||||
|
* have mismanaged the queues or completions are lost at the lower
|
||||||
|
* levels. When the removal and cancellation is completed this code
|
||||||
|
* will probably not be here. But for now just return.
|
||||||
|
*/
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( finalCachedCmd.getCommandstyle() == CommandStyle.COALESCED ) {
|
||||||
|
/*
|
||||||
|
* We matched a command which is itself already a COALESCED command. So
|
||||||
|
* we need to go throught the list of unsent commands which were not sent
|
||||||
|
* because the coalesced command represented it. For each match we find
|
||||||
|
* we create a new result from the coalesced command for it.
|
||||||
|
*/
|
||||||
|
ICommandResult result = getData();
|
||||||
|
|
||||||
|
for ( CommandInfo waitingEntry : new ArrayList<CommandInfo>(fPendingQWaitingForCoalescedCompletion) ) {
|
||||||
|
|
||||||
|
if ( waitingEntry.getCoalescedCmd() == finalCachedCmd ) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove this entry from the list since we can complete it.
|
||||||
|
*/
|
||||||
|
fPendingQWaitingForCoalescedCompletion.remove(waitingEntry);
|
||||||
|
|
||||||
|
// Cast the calculated result back to the requested type.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
V newresult = (V)result.getSubsetResult(waitingEntry.getCommand());
|
||||||
|
|
||||||
|
|
||||||
|
if(fCachedContexts.get(context) != null){
|
||||||
|
fCachedContexts.get(context).put(waitingEntry, newresult);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
HashMap<CommandInfo, ICommandResult> map = new HashMap<CommandInfo, ICommandResult>();
|
||||||
|
map.put(waitingEntry, newresult);
|
||||||
|
fCachedContexts.put(context, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getStatus().isOK()) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We had some form of error with the original command. So notify the
|
||||||
|
* original requestors of the issues.
|
||||||
|
*/
|
||||||
|
for (DataRequestMonitor<?> pendingRM : waitingEntry.getRequestMonitorList()) {
|
||||||
|
pendingRM.setStatus(getStatus());
|
||||||
|
pendingRM.done();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert newresult != null;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify the original requestors of the positive results.
|
||||||
|
*/
|
||||||
|
for (DataRequestMonitor<? extends ICommandResult> pendingRM : waitingEntry.getRequestMonitorList()) {
|
||||||
|
// Cast the pending return token to match the requested type.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
DataRequestMonitor<V> vPendingRM = (DataRequestMonitor<V>) pendingRM;
|
||||||
|
|
||||||
|
vPendingRM.setData(newresult);
|
||||||
|
vPendingRM.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* This is an original request which completed. Indicate success or
|
||||||
|
* failure to the original requestors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!getStatus().isOK()) {
|
||||||
|
/*
|
||||||
|
* We had some form of error with the original command. So notify the
|
||||||
|
* original requestors of the issues.
|
||||||
|
*/
|
||||||
|
for (DataRequestMonitor<?> pendingRM : finalCachedCmd.getRequestMonitorList()) {
|
||||||
|
pendingRM.setStatus(getStatus());
|
||||||
|
pendingRM.done();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Cast the calculated result back to the requested type.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
V result = (V)getData();
|
||||||
|
|
||||||
|
if(fCachedContexts.get(context) != null){
|
||||||
|
fCachedContexts.get(context).put(finalCachedCmd, result);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
HashMap<CommandInfo, ICommandResult> map = new HashMap<CommandInfo, ICommandResult>();
|
||||||
|
map.put(finalCachedCmd, result);
|
||||||
|
fCachedContexts.put(context, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DataRequestMonitor<? extends ICommandResult> pendingRM : finalCachedCmd.getRequestMonitorList()) {
|
||||||
|
// Cast the pending return token to match the requested type.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
DataRequestMonitor<V> vPendingRM = (DataRequestMonitor<V>) pendingRM;
|
||||||
|
|
||||||
|
vPendingRM.setData(result);
|
||||||
|
vPendingRM.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cache to a state in which target access is not allowed.
|
||||||
|
* When target is not available, commands to the target will either
|
||||||
|
* return data that is found in the cache already, or will return an
|
||||||
|
* error. This is useful in avoiding sending commands to target when
|
||||||
|
* they are known to fail or return unreliable results, while still
|
||||||
|
* providing access to the cached data.
|
||||||
|
*
|
||||||
|
* @param isAvailable Flag indicating whether target can be accessed.
|
||||||
|
*/
|
||||||
|
public void setTargetAvailable(boolean isAvailable) {
|
||||||
|
fIsTargetAvailable = isAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves current flag indicating target availability.
|
||||||
|
* @see #setTargetAvailable(boolean)
|
||||||
|
*/
|
||||||
|
public boolean isTargetAvailable() {
|
||||||
|
return fIsTargetAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the cache data.
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
|
fCachedContexts.clear();
|
||||||
|
fResetCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commandRemoved(ICommand<? extends ICommandResult> command) {
|
||||||
|
/*
|
||||||
|
* Do nothing.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandQueued(org.eclipse.dd.dsf.mi.core.command.ICommand)
|
||||||
|
*/
|
||||||
|
public void commandQueued(ICommand<? extends ICommandResult> command) {
|
||||||
|
/*
|
||||||
|
* Do nothing.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandDone(org.eclipse.dd.dsf.mi.core.command.ICommand, org.eclipse.dd.dsf.mi.core.command.ICommandResult)
|
||||||
|
*/
|
||||||
|
public void commandDone(ICommand<? extends ICommandResult> command, ICommandResult result) {
|
||||||
|
/*
|
||||||
|
* We handle the done with a runnable where we initiated the command
|
||||||
|
* so there is nothing to do here.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move the command into our internal sent list. This means we can no longer look at
|
||||||
|
* this command for possible coalescence since it has been given to the debug engine
|
||||||
|
* and is currently being processed.
|
||||||
|
*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.eclipse.dd.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandSent(org.eclipse.dd.dsf.mi.core.command.ICommand)
|
||||||
|
*/
|
||||||
|
public void commandSent(ICommand<? extends ICommandResult> command) {
|
||||||
|
|
||||||
|
// Cast the generic ?'s to concrete types in the cache implementation.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ICommand<ICommandResult> genericCommand = (ICommand<ICommandResult>)command;
|
||||||
|
|
||||||
|
CommandInfo cachedCmd = new CommandInfo( CommandStyle.NONCOALESCED, genericCommand, null) ;
|
||||||
|
|
||||||
|
for ( CommandInfo unqueuedCommand : new ArrayList<CommandInfo>(fPendingQCommandsNotYetSent) ) {
|
||||||
|
if ( unqueuedCommand.equals( cachedCmd )) {
|
||||||
|
fPendingQCommandsNotYetSent.remove(unqueuedCommand);
|
||||||
|
fPendingQCommandsSent.add(unqueuedCommand);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the cache entries for given context. Clears the whole cache if
|
||||||
|
* context parameter is null.
|
||||||
|
*/
|
||||||
|
public void reset(IDMContext dmc) {
|
||||||
|
if (dmc == null) {
|
||||||
|
fCachedContexts.clear();
|
||||||
|
}
|
||||||
|
for (Iterator<IDMContext> itr = fCachedContexts.keySet().iterator(); itr.hasNext();) {
|
||||||
|
IDMContext keyDmc = itr.next();
|
||||||
|
if (keyDmc != null && DMContexts.isAncestorOf(keyDmc, dmc)) {
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ package org.eclipse.dd.dsf.concurrent;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
import org.eclipse.core.runtime.MultiStatus;
|
import org.eclipse.core.runtime.MultiStatus;
|
||||||
import org.eclipse.dd.dsf.DsfPlugin;
|
import org.eclipse.dd.dsf.DsfPlugin;
|
||||||
|
|
||||||
|
@ -88,4 +89,12 @@ public class CountingRequestMonitor extends RequestMonitor {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CountingRequestMonitor: " + getStatus().toString(); //$NON-NLS-1$
|
return "CountingRequestMonitor: " + getStatus().toString(); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void setStatus(IStatus status) {
|
||||||
|
if (!(getStatus() instanceof MultiStatus)) {
|
||||||
|
super.setStatus(new MultiStatus(DsfPlugin.PLUGIN_ID, 0, "Combined status of multiple asynchronous operations", null)); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
((MultiStatus)getStatus()).add(status);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue