diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfCommandRunnable.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfCommandRunnable.java index 3ad8a811f20..3c925b0a819 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfCommandRunnable.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfCommandRunnable.java @@ -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) { diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfTerminateCommand.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfTerminateCommand.java deleted file mode 100644 index 40b954b4d0b..00000000000 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfTerminateCommand.java +++ /dev/null @@ -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(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; - } - -} diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java index b83c77bc4af..8b82bd70110 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java @@ -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; } diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IBreakpoints.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IBreakpoints.java index 0b2b47cfa0e..87114f4d5c2 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IBreakpoints.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IBreakpoints.java @@ -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 enum BreakpointStatus { INSTALLED, FAILED_TO_INSTALL, FILTERED_OUT } +public interface IBreakpoints extends IDsfService { + + /** + * 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 {} - - 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 rm); - public void getBreakpoints(IDMContext ctx, IBreakpoint platformBp, DataRequestMonitor 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); } diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMemory.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMemory.java index 24b1f4de6a7..e54ae738e94 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMemory.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMemory.java @@ -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. * diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/INativeProcesses.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/INativeProcesses.java deleted file mode 100644 index e71b08fd5f8..00000000000 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/INativeProcesses.java +++ /dev/null @@ -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 {} - - - public interface IProcessStartedEvent extends IDMEvent { - IProcessDMContext getProcess(); - } - - public interface IProcessExitedEvent extends IDMEvent { - IProcessDMContext getProcess(); - } - - public void getThreadData(IThreadDMContext dmc, DataRequestMonitor rm); - - public void getProcessData(IProcessDMContext dmc, DataRequestMonitor rm); - - - /** - * Returns a thread for the corresponding context. null if no corresponding - * thread exists. - * @param execCtx - * @return - */ - public IThreadDMContext getThreadForDebugContext(IDMContext execCtx); - - /** - * Returns a process context corresponding to the given context. null 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 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 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 rm); - - /** - * Retrieves the list of processes which are currently under - * debugger control. - * @param rm Request completion monitor. - */ - void getProcessesBeingDebugged(DataRequestMonitor 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 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); - -} diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/ISignals.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/ISignals.java new file mode 100644 index 00000000000..4ae9c3e3910 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/ISignals.java @@ -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 {}; + +} diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IStack.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IStack.java index 8a4180ad89c..49020ad4c25 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IStack.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IStack.java @@ -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 rm); - - void getStackDepth(int maxDepth, DataRequestMonitor rm); + void getStackDepth(IDMContext dmc, int maxDepth, DataRequestMonitor rm); } diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/command/CommandCache.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/command/CommandCache.java new file mode 100644 index 00000000000..5bdd7e9513f --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/command/CommandCache.java @@ -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 Type matches the result type associated with the command. + */ + class CommandInfo { + + /* + * Control variables. + */ + + /** List of the request monitors associated with this command */ + List> fCurrentRequestMonitors ; + + /** Original command. Need for reference from Queue completion notification */ + ICommand 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 cmd, DataRequestMonitor rm ) { + + fCmdStyle = cmdstyle; + fCommand = cmd; + fCurrentRequestMonitors = new LinkedList>(); + fCurrentRequestMonitors.add(rm); + fCoalescedCmd = null; + fResetCounterStatus = fResetCounter; + } + + public CommandStyle getCommandstyle() { return fCmdStyle; } + public List> getRequestMonitorList() { return fCurrentRequestMonitors; } + public ICommand 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> fCachedContexts = new HashMap>(); + + private ArrayList fPendingQCommandsSent = new ArrayList(); + + private ArrayList fPendingQCommandsNotYetSent = new ArrayList(); + + private ArrayList fPendingQWaitingForCoalescedCompletion = new ArrayList(); + + 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(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 coalescedCmd = + (ICommand)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(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 void execute(ICommand command, DataRequestMonitor rm) { + assert fCommandControl.getExecutor().isInExecutorThread(); + + // Cast the generic ?'s to concrete types in the cache implementation. + @SuppressWarnings("unchecked") + final ICommand genericCommand = (ICommand)command; + @SuppressWarnings("unchecked") + final DataRequestMonitor genericDone = (DataRequestMonitor) 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(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(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 map = new HashMap(); + 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 pendingRM : waitingEntry.getRequestMonitorList()) { + // Cast the pending return token to match the requested type. + @SuppressWarnings("unchecked") + DataRequestMonitor vPendingRM = (DataRequestMonitor) 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 map = new HashMap(); + map.put(finalCachedCmd, result); + fCachedContexts.put(context, map); + } + + for (DataRequestMonitor pendingRM : finalCachedCmd.getRequestMonitorList()) { + // Cast the pending return token to match the requested type. + @SuppressWarnings("unchecked") + DataRequestMonitor vPendingRM = (DataRequestMonitor) 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 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 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 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 command) { + + // Cast the generic ?'s to concrete types in the cache implementation. + @SuppressWarnings("unchecked") + ICommand genericCommand = (ICommand)command; + + CommandInfo cachedCmd = new CommandInfo( CommandStyle.NONCOALESCED, genericCommand, null) ; + + for ( CommandInfo unqueuedCommand : new ArrayList(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 itr = fCachedContexts.keySet().iterator(); itr.hasNext();) { + IDMContext keyDmc = itr.next(); + if (keyDmc != null && DMContexts.isAncestorOf(keyDmc, dmc)) { + itr.remove(); + } + } + } +} diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/CountingRequestMonitor.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/CountingRequestMonitor.java index 0fabdafb7da..736dc3cc957 100644 --- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/CountingRequestMonitor.java +++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/CountingRequestMonitor.java @@ -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); + }; }