1
0
Fork 0
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:
Pawel Piech 2007-11-14 00:16:00 +00:00
parent 18fd2d6ef6
commit 1d31b66b19
10 changed files with 586 additions and 271 deletions

View file

@ -15,7 +15,6 @@ import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.Immutable;
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.IStepQueueManager;
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
@ -40,10 +39,6 @@ public abstract class DsfCommandRunnable extends DsfRunnable {
return fTracker.getService(IStepQueueManager.class);
}
public INativeProcesses getProcesses() {
return fTracker.getService(INativeProcesses.class);
}
public DsfCommandRunnable(DsfServicesTracker servicesTracker, Object element, IDebugCommandRequest request) {
fTracker = servicesTracker;
if (element instanceof DMVMContext) {

View file

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

View file

@ -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.IFormattedValues.FormattedValueDMContext;
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.IDsfService;
import org.eclipse.debug.core.DebugException;
@ -66,7 +67,7 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl
private final String fModelId;
private final DsfSession fSession;
private final DsfExecutor fExecutor;
private IDMContext fContext;
private IMemoryDMContext fContext;
private final ServiceTracker fMemoryServiceTracker;
private final ServiceTracker fExpressionServiceTracker;
@ -77,7 +78,7 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl
* @param dmc
* @throws DebugException
*/
public DsfMemoryBlockRetrieval(String modelId, IDMContext dmc) throws DebugException {
public DsfMemoryBlockRetrieval(String modelId, IMemoryDMContext dmc) throws DebugException {
fModelId = modelId;
fContext = dmc;
@ -263,11 +264,8 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl
return null;
}
// Update the DMC
fContext = dmc;
// Resolve the expression
blockAddress = resolveMemoryAddress(fContext, expression);
blockAddress = resolveMemoryAddress(dmc, expression);
if (blockAddress == null) {
return null;
}

View file

@ -10,12 +10,9 @@
*******************************************************************************/
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;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.dd.dsf.service.IDsfService;
/**
* 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
* 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();
BreakpointStatus getStatus();
}
public interface IBreakpointDMEvent extends IDMEvent<IBreakpointDMContext> {}
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);
/**
* Uninstall and stop tracking breakpoints for the given context.
* @param dmc Context to start tracking breakpoints for.
* @param rm Completion callback.
*/
public void uninstallBreakpoints(IDMContext dmc, RequestMonitor rm);
}

View file

@ -26,6 +26,8 @@ import org.eclipse.debug.core.model.MemoryByte;
*/
public interface IMemory extends IDsfService {
public interface IMemoryDMContext extends IDMContext {}
/**
* Event generated every time a range of bytes is modified.
*

View file

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

View file

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

View file

@ -104,10 +104,12 @@ public interface IStack extends IDMService {
/**
* 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(int maxDepth, DataRequestMonitor<Integer> rm);
void getStackDepth(IDMContext dmc, int maxDepth, DataRequestMonitor<Integer> rm);
}

View file

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

View file

@ -12,6 +12,7 @@ package org.eclipse.dd.dsf.concurrent;
import java.util.concurrent.Executor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.dd.dsf.DsfPlugin;
@ -88,4 +89,12 @@ public class CountingRequestMonitor extends RequestMonitor {
public String toString() {
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);
};
}