From c61de9929cd903c180d406c796d52d381f58d2a5 Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Tue, 12 Feb 2008 23:04:12 +0000 Subject: [PATCH] [218560] Replaced IStepQueueManager with a concrete generic implementation StepQueueManager. --- .../debug/ui/actions/DsfCommandRunnable.java | 6 +- .../sourcelookup/MISourceDisplayAdapter.java | 4 +- .../dsf/debug/service/IStepQueueManager.java | 73 ----- .../dsf/debug/service/StepQueueManager.java | 258 ++++++++++++++++++ 4 files changed, 263 insertions(+), 78 deletions(-) delete mode 100644 plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IStepQueueManager.java create mode 100644 plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/StepQueueManager.java 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 42f870b9f1d..cd05575d3bc 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 @@ -16,7 +16,7 @@ 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.IRunControl; -import org.eclipse.dd.dsf.debug.service.IStepQueueManager; +import org.eclipse.dd.dsf.debug.service.StepQueueManager; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; import org.eclipse.dd.dsf.service.DsfServicesTracker; @@ -33,8 +33,8 @@ public abstract class DsfCommandRunnable extends DsfRunnable { public IRunControl getRunControl() { return fTracker.getService(IRunControl.class); } - public IStepQueueManager getStepQueueMgr() { - return fTracker.getService(IStepQueueManager.class); + public StepQueueManager getStepQueueMgr() { + return fTracker.getService(StepQueueManager.class); } public DsfCommandRunnable(DsfServicesTracker servicesTracker, Object element, IDebugCommandRequest request) { diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/MISourceDisplayAdapter.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/MISourceDisplayAdapter.java index 3b51b20ed0f..b4689d6e5b6 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/MISourceDisplayAdapter.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/MISourceDisplayAdapter.java @@ -31,7 +31,7 @@ import org.eclipse.dd.dsf.datamodel.DMContexts; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl; import org.eclipse.dd.dsf.debug.service.IStack; -import org.eclipse.dd.dsf.debug.service.IStepQueueManager; +import org.eclipse.dd.dsf.debug.service.StepQueueManager; import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMData; @@ -543,7 +543,7 @@ public class MISourceDisplayAdapter implements ISourceDisplay } @DsfServiceEventHandler - public void eventDispatched(IStepQueueManager.ISteppingTimedOutEvent e) { + public void eventDispatched(StepQueueManager.ISteppingTimedOutEvent e) { startAnnotationClearingJob(e.getDMContext()); } } diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IStepQueueManager.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IStepQueueManager.java deleted file mode 100644 index 3a654c33e62..00000000000 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IStepQueueManager.java +++ /dev/null @@ -1,73 +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.datamodel.IDMEvent; -import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.dsf.service.IDsfService; - -/** - * This service builds on top of standard run control service to provide - * step queuing functionality. Step queuing essentially allows user to press - * and hold the step key and achieve maximum stepping speed. If this service - * is used, other service implementations, such as stack and expressions, can - * use it to avoid requesting data from debugger back end if another step is - * about to be executed. - */ -public interface IStepQueueManager extends IDsfService { - /** - * Amount of time in miliseconds, that it takes the ISteppingTimedOutEvent - * event to be issued after a step is started. - * @see ISteppingTimedOutEvent - */ - public final static int STEPPING_TIMEOUT = 500; - - /** - * Indicates that the given context has been stepping for some time, - * and the UI (views and actions) may need to be updated accordingly. - */ - public interface ISteppingTimedOutEvent extends IDMEvent { - } - - - void setStepQueueDepth(int depth); - int getStepQueueDepth(); - - /** - * Returns the number of step commands that are queued for given execution - * context. - */ - int getPendingStepCount(IExecutionDMContext ctx); - - /** - * Checks whether a step command can be queued up for given context. - */ - boolean canEnqueueStep(IExecutionDMContext execCtx); - - boolean canEnqueueInstructionStep(IExecutionDMContext ctx); - - /** - * Adds a step command to the execution queue for given context. - * @param execCtx Execution context that should perform the step. - * @param stepType Type of step to execute. - */ - void enqueueStep(IExecutionDMContext ctx, IRunControl.StepType stepType); - - /** - * Adds an instruction step command to the execution queue for given - * context. - * @param execCtx Execution context that should perform the step. - * @param stepType Type of step to execute. - */ - void enqueueInstructionStep(IExecutionDMContext ctx, IRunControl.StepType stepType); - - boolean isSteppingTimedOut(IExecutionDMContext context); -} diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/StepQueueManager.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/StepQueueManager.java new file mode 100644 index 00000000000..c46b28611f7 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/StepQueueManager.java @@ -0,0 +1,258 @@ +/******************************************************************************* + * 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 java.util.HashMap; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.IDMEvent; +import org.eclipse.dd.dsf.debug.DsfDebugPlugin; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IResumedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.debug.service.IRunControl.StepType; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.osgi.framework.BundleContext; + +/** + * This service builds on top of standard run control service to provide + * step queuing functionality. Step queuing essentially allows user to press + * and hold the step key and achieve maximum stepping speed. If this service + * is used, other service implementations, such as stack and expressions, can + * use it to avoid requesting data from debugger back end if another step is + * about to be executed. + */ +public class StepQueueManager extends AbstractDsfService +{ + /** + * Amount of time in miliseconds, that it takes the ISteppingTimedOutEvent + * event to be issued after a step is started. + * @see ISteppingTimedOutEvent + */ + public final static int STEPPING_TIMEOUT = 500; + + /** + * The depth of the step queue. In other words, the maximum number of steps + * that are queued before the step queue manager throwing them away. + */ + public final static int STEP_QUEUE_DEPTH = 3; + + /** + * Indicates that the given context has been stepping for some time, + * and the UI (views and actions) may need to be updated accordingly. + */ + public interface ISteppingTimedOutEvent extends IDMEvent {} + + + private static class StepRequest { + StepType fStepType; + boolean fIsInstructionStep; + StepRequest(StepType type, boolean instruction) { + fStepType = type; + fIsInstructionStep = instruction; + } + } + + private IRunControl fRunControl; + private int fQueueDepth = STEP_QUEUE_DEPTH; + private Map> fStepQueues = new HashMap>(); + private Map fTimedOutFlags = new HashMap(); + private Map> fTimedOutFutures = new HashMap>(); + + public StepQueueManager(DsfSession session) { + super(session); + } + + /////////////////////////////////////////////////////////////////////////// + // IDsfService + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + doInitialize(requestMonitor); + }}); + } + + private void doInitialize(final RequestMonitor requestMonitor) { + fRunControl = getServicesTracker().getService(IRunControl.class); + + getSession().addServiceEventListener(this, null); + register(new String[]{ StepQueueManager.class.getName()}, new Hashtable()); + requestMonitor.done(); + } + + @Override + public void shutdown(final RequestMonitor requestMonitor) { + unregister(); + getSession().removeServiceEventListener(this); + super.shutdown(requestMonitor); + } + + @Override + protected BundleContext getBundleContext() { + return DsfDebugPlugin.getBundleContext(); + } + + /** + * Checks whether a step command can be queued up for given context. + */ + public boolean canEnqueueStep(IExecutionDMContext execCtx) { + return (fRunControl.isSuspended(execCtx) && fRunControl.canStep(execCtx)) || + (fRunControl.isStepping(execCtx) && !isSteppingTimedOut(execCtx)); + } + + /** + * Checks whether an instruction step command can be queued up for given context. + */ + public boolean canEnqueueInstructionStep(IExecutionDMContext execCtx) { + return (fRunControl.isSuspended(execCtx) && fRunControl.canInstructionStep(execCtx)) || + (fRunControl.isStepping(execCtx) && !isSteppingTimedOut(execCtx)); + } + + /** + * Returns the number of step commands that are queued for given execution + * context. + */ + public int getPendingStepCount(IExecutionDMContext execCtx) { + List stepQueue = fStepQueues.get(execCtx); + if (stepQueue == null) return 0; + return stepQueue.size(); + } + + /** + * Adds a step command to the execution queue for given context. + * @param execCtx Execution context that should perform the step. + * @param stepType Type of step to execute. + */ + public void enqueueStep(IExecutionDMContext execCtx, StepType stepType) { + if (fRunControl.canStep(execCtx)) { + fRunControl.step(execCtx, stepType, new RequestMonitor(getExecutor(), null)); + } else if (canEnqueueStep(execCtx)) { + List stepQueue = fStepQueues.get(execCtx); + if (stepQueue == null) { + stepQueue = new LinkedList(); + fStepQueues.put(execCtx, stepQueue); + } + if (stepQueue.size() < fQueueDepth) { + stepQueue.add(new StepRequest(stepType, false)); + } + } + } + + /** + * Adds an instruction step command to the execution queue for given + * context. + * @param execCtx Execution context that should perform the step. + * @param stepType Type of step to execute. + */ + public void enqueueInstructionStep(IExecutionDMContext execCtx, StepType stepType) { + if (fRunControl.canInstructionStep(execCtx)) { + fRunControl.instructionStep(execCtx, stepType, new RequestMonitor(getExecutor(), null)); + } else if (canEnqueueInstructionStep(execCtx)) { + List stepQueue = fStepQueues.get(execCtx); + if (stepQueue == null) { + stepQueue = new LinkedList(); + fStepQueues.put(execCtx, stepQueue); + } + if (stepQueue.size() < fQueueDepth) { + stepQueue.add(new StepRequest(stepType, true)); + } + } + } + + /** + * Returns whether the step instruction for the given context has timed out. + */ + public boolean isSteppingTimedOut(IExecutionDMContext execCtx) { + return fTimedOutFlags.containsKey(execCtx) ? fTimedOutFlags.get(execCtx) : false; + } + + + /////////////////////////////////////////////////////////////////////////// + + @DsfServiceEventHandler + public void eventDispatched(ISuspendedDMEvent e) { + // Take care of the stepping time out + fTimedOutFlags.remove(e.getDMContext()); + ScheduledFuture future = fTimedOutFutures.remove(e.getDMContext()); + if (future != null) future.cancel(false); + + // Check if there's a step pending, if so execute it + if (fStepQueues.containsKey(e.getDMContext())) { + List queue = fStepQueues.get(e.getDMContext()); + StepRequest request = queue.remove(queue.size() - 1); + if (queue.isEmpty()) fStepQueues.remove(e.getDMContext()); + if (request.fIsInstructionStep) { + if (fRunControl.canInstructionStep(e.getDMContext())) { + fRunControl.instructionStep( + e.getDMContext(), request.fStepType, new RequestMonitor(getExecutor(), null)); + } else { + // For whatever reason we can't step anymore, so clear out + // the step queue. + fStepQueues.remove(e.getDMContext()); + } + } else { + if (fRunControl.canStep(e.getDMContext())) { + fRunControl.step(e.getDMContext(), request.fStepType,new RequestMonitor(getExecutor(), null)); + } else { + // For whatever reason we can't step anymore, so clear out + // the step queue. + fStepQueues.remove(e.getDMContext()); + } + } + } + } + + @DsfServiceEventHandler + public void eventDispatched(final IResumedDMEvent e) { + if (e.getReason().equals(StateChangeReason.STEP)) { + fTimedOutFlags.put(e.getDMContext(), Boolean.FALSE); + // We shouldn't have a stepping timeout running unless we get two + // stepping events in a row without a suspended, which would be a + // protocol error. + assert !fTimedOutFutures.containsKey(e.getDMContext()); + fTimedOutFutures.put( + e.getDMContext(), + getExecutor().schedule( + new DsfRunnable() { public void run() { + fTimedOutFutures.remove(e.getDMContext()); + + // Issue the stepping time-out event. + getSession().dispatchEvent( + new ISteppingTimedOutEvent() { + public IExecutionDMContext getDMContext() { return e.getDMContext(); } + }, + getProperties()); + }}, + STEPPING_TIMEOUT, TimeUnit.MILLISECONDS) + ); + + } + } + + @DsfServiceEventHandler + public void eventDispatched(ISteppingTimedOutEvent e) { + fTimedOutFlags.put(e.getDMContext(), Boolean.TRUE); + } + +}