Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2008-07-09 16:45:34 +0000
committereutarass2008-07-09 16:45:34 +0000
commit67ad4de442d3a8d76c1ecfe777122cb0457017e0 (patch)
tree87be9df227fe2273ab29351bcbb701b1a10fc97a
parent7ed998ec71c68d95c0da3e678e403f9e7cf5a298 (diff)
downloadorg.eclipse.tcf-67ad4de442d3a8d76c1ecfe777122cb0457017e0.tar.gz
org.eclipse.tcf-67ad4de442d3a8d76c1ecfe777122cb0457017e0.tar.xz
org.eclipse.tcf-67ad4de442d3a8d76c1ecfe777122cb0457017e0.zip
1. Added Protocol.invokeLater() method that dispatches an event with given delay
2. Moved source level stepping and related logic to non-UI plug-in, made it reusable. 3. Added source level stepping support into DSF integration.
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java4
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java228
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java290
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java179
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java135
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java10
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java65
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java5
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/META-INF/MANIFEST.MF1
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFAction.java45
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepInto.java224
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOut.java170
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOver.java290
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFContextState.java22
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java71
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java (renamed from plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java)2
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/AdapterFactory.java1
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/ExecutableContextLayoutNode.java100
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/LaunchVMProvider.java2
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFLaunchSequence.java2
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFSourceLookupParticipant.java34
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFExecutionDMC.java13
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControl.java315
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControlState.java19
-rw-r--r--plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java215
-rw-r--r--plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/Protocol.java100
27 files changed, 1635 insertions, 913 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java
index 07292e45d..39b19894c 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java
@@ -14,9 +14,9 @@ import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandHandler;
import org.eclipse.debug.core.commands.IDebugCommandRequest;
import org.eclipse.debug.core.commands.IEnabledStateRequest;
-import org.eclipse.debug.core.commands.IStepOverHandler;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.tm.internal.tcf.debug.ui.Activator;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModel;
@@ -25,7 +25,7 @@ import org.eclipse.tm.internal.tcf.debug.ui.model.TCFRunnable;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IRunControl;
-abstract class StepCommand implements IStepOverHandler {
+abstract class StepCommand implements IDebugCommandHandler {
protected final TCFModel model;
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java
index 941100bf1..ef1dd6296 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepIntoCommand.java
@@ -10,226 +10,80 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.commands;
-import java.math.BigInteger;
-import java.util.Map;
-
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.commands.IDebugCommandRequest;
import org.eclipse.debug.core.commands.IStepIntoHandler;
+import org.eclipse.tm.internal.tcf.debug.actions.TCFActionStepInto;
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
import org.eclipse.tm.internal.tcf.debug.ui.Activator;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModel;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeExecContext;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeStackFrame;
-import org.eclipse.tm.internal.tcf.debug.ui.model.TCFSourceRef;
-import org.eclipse.tm.tcf.protocol.IToken;
-import org.eclipse.tm.tcf.protocol.Protocol;
-import org.eclipse.tm.tcf.services.ILineNumbers;
import org.eclipse.tm.tcf.services.IRunControl;
-import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.services.IStackTrace.StackTraceContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
public class StepIntoCommand extends StepCommand implements IStepIntoHandler {
- private static final long TIMEOUT = 10000;
-
- private static class StepStateMachine extends TCFModel.ContextAction implements IRunControl.RunControlListener {
+ private static class StepStateMachine extends TCFActionStepInto {
private final IDebugCommandRequest monitor;
- private final boolean src_step;
private final Runnable done;
- private final IRunControl rc = model.getLaunch().getService(IRunControl.class);
-
- private IRunControl.RunControlContext ctx;
- private TCFNodeExecContext node;
+ private final TCFNodeExecContext node;
private TCFNodeStackFrame frame;
- private TCFSourceRef line_info;
- private BigInteger pc0;
- private BigInteger pc1;
- private int step_cnt;
- private boolean started;
- private boolean exited;
StepStateMachine(TCFModel model, IDebugCommandRequest monitor,
- IRunControl.RunControlContext ctx,
- boolean src_step, Runnable done) {
- super(model, ctx.getID());
+ IRunControl.RunControlContext ctx, boolean src_step, Runnable done) {
+ super(model.getLaunch(), ctx, src_step);
this.monitor = monitor;
- this.ctx = ctx;
- this.src_step = src_step;
this.done = done;
+ node = (TCFNodeExecContext)model.getNode(context_id);
}
- public void run() {
- assert !exited;
- if (!started) {
- started = true;
- rc.addListener(this);
- node = (TCFNodeExecContext)model.getNode(ctx.getID());
- if (node == null) {
- exit(new Exception("Invalid context ID"));
- return;
- }
- if (!ctx.canResume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO)) {
- model.invokeLater(TIMEOUT, new Runnable() {
- public void run() {
- exit(new Exception("Time out"));
- }
- });
- }
- }
- if (!node.validateNode(this)) return;
- if (!node.isSuspended()) {
- exit(new Exception("Context is not suspended"));
- return;
- }
- if (ctx.canResume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO)) {
- if (step_cnt > 0) return;
- ctx.resume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- exit(error);
- }
- });
- step_cnt++;
- return;
- }
- if (!src_step) {
- exit(new Exception("Step into is not supported"));
- return;
- }
- if (frame == null) {
- frame = node.getTopFrame();
- if (frame == null) {
- exit(new Exception("Cannot get top stack frame"));
- return;
- }
- }
- if (frame.getFrameNo() >= 0 && !frame.validateNode(this)) return;
- if (line_info == null) {
- assert frame.getFrameNo() == 0;
- line_info = frame.getLineInfo().getData();
- if (line_info == null) {
- exit(new Exception("Line info not available"));
- return;
- }
- if (line_info.error != null) {
- exit(line_info.error);
- return;
- }
- ILineNumbers.CodeArea area = line_info.area;
- if (area != null) {
- if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
- else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
- if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
- else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
- }
- }
- if (frame.getFrameNo() != 0) {
- // Stepped out of selected function
- exit(null);
- return;
- }
- if (step_cnt > 0) {
- BigInteger pc = node.getAddress();
- if (pc == null || pc0 == null || pc1 == null) {
- exit(null);
- return;
- }
- if (pc.compareTo(pc0) < 0 || pc.compareTo(pc1) >= 0) {
- TCFSourceRef ref = frame.getLineInfo().getData();
- if (ref != null && ref.area != null) {
- if (isSameLine(line_info.area, ref.area)) {
- line_info = ref;
- ILineNumbers.CodeArea area = line_info.area;
- if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
- else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
- if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
- else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
- }
- else {
- exit(null);
- return;
- }
- }
- }
- }
- step_cnt++;
- if (ctx.canResume(IRunControl.RM_STEP_INTO)) {
- ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- }
- else {
- exit(new Exception("Step into is not supported"));
- }
- }
-
- private boolean isSameLine(ILineNumbers.CodeArea x, ILineNumbers.CodeArea y) {
- if (x == null || y == null) return false;
- if (x.start_line != y.start_line) return false;
- if (x.directory != y.directory && (x.directory == null || !x.directory.equals(y.directory))) return false;
- if (x.file != y.file && (x.file == null || !x.file.equals(y.file))) return false;
- return true;
- }
-
- private void exit(Throwable error) {
- assert started;
- if (exited) return;
- rc.removeListener(this);
- exited = true;
- if (error != null) {
- monitor.setStatus(new Status(IStatus.ERROR,
- Activator.PLUGIN_ID, IStatus.OK, "Cannot step", error));
- }
- done.run();
- done();
- }
-
- public void containerResumed(String[] context_ids) {
- }
-
- public void containerSuspended(String context, String pc,
- String reason, Map<String, Object> params,
- String[] suspended_ids) {
- for (String id : suspended_ids) {
- if (!id.equals(context)) contextSuspended(id, null, null, null);
- }
- contextSuspended(context, pc, reason, params);
+ @Override
+ protected TCFDataCache<TCFContextState> getContextState() {
+ if (node == null) return null;
+ return node.getState();
}
- public void contextAdded(RunControlContext[] contexts) {
+ @Override
+ protected TCFDataCache<TCFSourceRef> getLineInfo() {
+ if (frame == null) frame = node.getTopFrame();
+ if (frame == null) return null;
+ return frame.getLineInfo();
}
- public void contextChanged(RunControlContext[] contexts) {
- for (RunControlContext c : contexts) {
- if (c.getID().equals(ctx.getID())) ctx = c;
- }
+ @Override
+ protected TCFDataCache<StackTraceContext> getStackFrame() {
+ if (frame == null) frame = node.getTopFrame();
+ if (frame == null) return null;
+ return frame.getStackTraceContext();
}
- public void contextException(String context, String msg) {
- if (context.equals(ctx.getID())) exit(new Exception(msg));
+ @Override
+ protected int getStackFrameIndex() {
+ if (frame == null) frame = node.getTopFrame();
+ if (frame == null) return 0;
+ return frame.getFrameNo();
}
- public void contextRemoved(String[] context_ids) {
- for (String context : context_ids) {
- if (context.equals(ctx.getID())) exit(null);
- }
+ @Override
+ protected TCFDataCache<?> getStackTrace() {
+ return node.getStackTrace();
}
-
- public void contextResumed(String context) {
- }
-
- public void contextSuspended(String context, String pc, String reason,
- Map<String, Object> params) {
- if (!context.equals(ctx.getID())) return;
- if (IRunControl.REASON_STEP.equals(reason)) {
- Protocol.invokeLater(this);
- }
- else {
- exit(null);
+
+ @Override
+ protected void exit(Throwable error) {
+ if (exited) return;
+ super.exit(error);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ Activator.PLUGIN_ID, IStatus.OK, "Cannot step", error));
}
+ done.run();
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java
index c71a48a73..6a0071dfe 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepOverCommand.java
@@ -10,292 +10,82 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.commands;
-import java.math.BigInteger;
-import java.util.HashMap;
-import java.util.Map;
-
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.commands.IDebugCommandRequest;
import org.eclipse.debug.core.commands.IStepOverHandler;
+import org.eclipse.tm.internal.tcf.debug.actions.TCFActionStepOver;
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
import org.eclipse.tm.internal.tcf.debug.ui.Activator;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModel;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeExecContext;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeStackFrame;
-import org.eclipse.tm.internal.tcf.debug.ui.model.TCFSourceRef;
-import org.eclipse.tm.tcf.protocol.IToken;
-import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IBreakpoints;
-import org.eclipse.tm.tcf.services.ILineNumbers;
import org.eclipse.tm.tcf.services.IRunControl;
-import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.services.IStackTrace.StackTraceContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
public class StepOverCommand extends StepCommand implements IStepOverHandler {
- private static final long TIMEOUT = 10000;
-
- private static class StepStateMachine extends TCFModel.ContextAction implements IRunControl.RunControlListener {
+ private static class StepStateMachine extends TCFActionStepOver {
private final IDebugCommandRequest monitor;
- private final boolean src_step;
private final Runnable done;
- private final IRunControl rc = model.getLaunch().getService(IRunControl.class);
- private final IBreakpoints bps = model.getLaunch().getService(IBreakpoints.class);
-
- private IRunControl.RunControlContext ctx;
- private TCFNodeExecContext node;
+ private final TCFNodeExecContext node;
private TCFNodeStackFrame frame;
- private TCFSourceRef line_info;
- private BigInteger pc0;
- private BigInteger pc1;
- private int step_cnt;
- private Map<String,Object> bp;
- private boolean started;
- private boolean exited;
StepStateMachine(TCFModel model, IDebugCommandRequest monitor,
IRunControl.RunControlContext ctx,
boolean src_step, Runnable done) {
- super(model, ctx.getID());
+ super(model.getLaunch(), ctx, src_step);
this.monitor = monitor;
- this.ctx = ctx;
- this.src_step = src_step;
this.done = done;
- }
-
- public void run() {
- assert !exited;
- if (!started) {
- started = true;
- rc.addListener(this);
- node = (TCFNodeExecContext)model.getNode(ctx.getID());
- if (node == null) {
- exit(new Exception("Invalid context ID"));
- return;
- }
- if (!ctx.canResume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER)) {
- model.invokeLater(TIMEOUT, new Runnable() {
- public void run() {
- exit(new Exception("Time out"));
- }
- });
- }
- }
- if (!node.validateNode(this)) return;
- if (!node.isSuspended()) {
- exit(new Exception("Context is not suspended"));
- return;
- }
- if (ctx.canResume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER)) {
- if (step_cnt > 0) return;
- ctx.resume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- exit(error);
- }
- });
- step_cnt++;
- return;
- }
- if (frame == null) {
- frame = node.getTopFrame();
- if (frame == null) {
- exit(new Exception("Cannot get top stack frame"));
- return;
- }
- }
- if (frame.getFrameNo() >= 0 && !frame.validateNode(this)) return;
- if (src_step && line_info == null) {
- assert frame.getFrameNo() == 0;
- line_info = frame.getLineInfo().getData();
- if (line_info == null) {
- exit(new Exception("Line info not available"));
- return;
- }
- if (line_info.error != null) {
- exit(line_info.error);
- return;
- }
- ILineNumbers.CodeArea area = line_info.area;
- if (area != null) {
- if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
- else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
- if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
- else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
- }
- }
- if (frame.getFrameNo() != 0) {
- if (frame.getFrameNo() < 0) {
- // Stepped out of selected function
- exit(null);
- }
- else if (ctx.canResume(IRunControl.RM_STEP_OUT)) {
- ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- }
- else if (bps != null && ctx.canResume(IRunControl.RM_RESUME)) {
- if (bp == null) {
- BigInteger addr = frame.getAddress();
- if (addr == null) {
- exit(new Exception("Unknown PC address"));
- return;
- }
- bp = new HashMap<String,Object>();
- bp.put(IBreakpoints.PROP_ID, "Step" + System.currentTimeMillis());
- bp.put(IBreakpoints.PROP_LOCATION, addr.toString());
- bp.put(IBreakpoints.PROP_CONDITION, "$thread==\"" + ctx.getID() + "\"");
- bp.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
- bps.add(bp, new IBreakpoints.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- }
- ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- }
- else {
- exit(new Exception("Step over is not supported"));
- }
- return;
- }
- if (bp != null) {
- bps.remove(new String[]{ (String)bp.get(IBreakpoints.PROP_ID) }, new IBreakpoints.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- bp = null;
- }
- if (step_cnt > 0) {
- BigInteger pc = node.getAddress();
- if (pc == null || pc0 == null || pc1 == null) {
- exit(null);
- return;
- }
- if (pc.compareTo(pc0) < 0 || pc.compareTo(pc1) >= 0) {
- TCFSourceRef ref = frame.getLineInfo().getData();
- if (ref != null && ref.area != null) {
- if (isSameLine(line_info.area, ref.area)) {
- line_info = ref;
- ILineNumbers.CodeArea area = line_info.area;
- if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
- else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
- if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
- else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
- }
- else {
- exit(null);
- return;
- }
- }
- }
- }
- step_cnt++;
- if (ctx.canResume(IRunControl.RM_STEP_OVER)) {
- ctx.resume(IRunControl.RM_STEP_OVER, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- }
- else if (ctx.canResume(IRunControl.RM_STEP_INTO)) {
- ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- }
- else {
- exit(new Exception("Step over is not supported"));
- }
- }
-
- private void exit(Throwable error) {
- assert started;
- if (exited) return;
- if (bp != null) {
- bps.remove(new String[]{ (String)bp.get(IBreakpoints.PROP_ID) }, new IBreakpoints.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- }
- });
- }
- rc.removeListener(this);
- exited = true;
- if (error != null) {
- monitor.setStatus(new Status(IStatus.ERROR,
- Activator.PLUGIN_ID, IStatus.OK, "Cannot step", error));
- }
- done.run();
- done();
+ node = (TCFNodeExecContext)model.getNode(context_id);
}
- public void containerResumed(String[] context_ids) {
- }
-
- public void containerSuspended(String context, String pc,
- String reason, Map<String, Object> params,
- String[] suspended_ids) {
- for (String id : suspended_ids) {
- if (!id.equals(context)) contextSuspended(id, null, null, null);
- }
- contextSuspended(context, pc, reason, params);
- }
-
- public void contextAdded(RunControlContext[] contexts) {
- }
-
- public void contextChanged(RunControlContext[] contexts) {
- for (RunControlContext c : contexts) {
- if (c.getID().equals(ctx.getID())) ctx = c;
- }
+ @Override
+ protected TCFDataCache<TCFContextState> getContextState() {
+ if (node == null) return null;
+ return node.getState();
}
- public void contextException(String context, String msg) {
- if (context.equals(ctx.getID())) exit(new Exception(msg));
+ @Override
+ protected TCFDataCache<TCFSourceRef> getLineInfo() {
+ if (frame == null) frame = node.getTopFrame();
+ if (frame == null) return null;
+ return frame.getLineInfo();
}
- public void contextRemoved(String[] context_ids) {
- for (String context : context_ids) {
- if (context.equals(ctx.getID())) exit(null);
- }
+ @Override
+ protected TCFDataCache<StackTraceContext> getStackFrame() {
+ if (frame == null) frame = node.getTopFrame();
+ if (frame == null) return null;
+ return frame.getStackTraceContext();
}
- public void contextResumed(String context) {
+ @Override
+ protected int getStackFrameIndex() {
+ if (frame == null) frame = node.getTopFrame();
+ if (frame == null) return 0;
+ return frame.getFrameNo();
}
- public void contextSuspended(String context, String pc, String reason,
- Map<String, Object> params) {
- if (!context.equals(ctx.getID())) return;
- if (IRunControl.REASON_STEP.equals(reason) || isMyBreakpoint(pc, reason)) {
- Protocol.invokeLater(this);
- }
- else {
- exit(null);
- }
+ @Override
+ protected TCFDataCache<?> getStackTrace() {
+ return node.getStackTrace();
}
- private boolean isSameLine(ILineNumbers.CodeArea x, ILineNumbers.CodeArea y) {
- if (x == null || y == null) return false;
- if (x.start_line != y.start_line) return false;
- if (x.directory != y.directory && (x.directory == null || !x.directory.equals(y.directory))) return false;
- if (x.file != y.file && (x.file == null || !x.file.equals(y.file))) return false;
- return true;
- }
-
- private boolean isMyBreakpoint(String pc, String reason) {
- if (bp == null) return false;
- if (pc == null) return false;
- if (!IRunControl.REASON_BREAKPOINT.equals(reason)) return false;
- BigInteger x = new BigInteger(pc);
- BigInteger y = new BigInteger((String)bp.get(IBreakpoints.PROP_LOCATION));
- return x.equals(y);
+ @Override
+ protected void exit(Throwable error) {
+ if (exited) return;
+ super.exit(error);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ Activator.PLUGIN_ID, IStatus.OK, "Cannot step", error));
+ }
+ done.run();
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java
index 45c9aaca6..557114167 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepReturnCommand.java
@@ -10,182 +10,73 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.commands;
-import java.math.BigInteger;
-import java.util.HashMap;
-import java.util.Map;
-
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.commands.IDebugCommandRequest;
import org.eclipse.debug.core.commands.IStepReturnHandler;
+import org.eclipse.tm.internal.tcf.debug.actions.TCFActionStepOut;
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
import org.eclipse.tm.internal.tcf.debug.ui.Activator;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModel;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeExecContext;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeStackFrame;
-import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.services.IBreakpoints;
import org.eclipse.tm.tcf.services.IRunControl;
-import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.services.IStackTrace.StackTraceContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
public class StepReturnCommand extends StepCommand implements IStepReturnHandler {
- private static final long TIMEOUT = 10000;
-
- private static class StepStateMachine extends TCFModel.ContextAction implements IRunControl.RunControlListener {
+ private static class StepStateMachine extends TCFActionStepOut {
private final IDebugCommandRequest monitor;
private final Runnable done;
- private final IRunControl rc = model.getLaunch().getService(IRunControl.class);
- private final IBreakpoints bps = model.getLaunch().getService(IBreakpoints.class);
-
- private IRunControl.RunControlContext ctx;
- private TCFNodeExecContext node;
+ private final TCFNodeExecContext node;
private TCFNodeStackFrame frame;
- private int step_cnt;
- private Map<String,Object> bp;
- private boolean started;
- private boolean exited;
-
+
StepStateMachine(TCFModel model, IDebugCommandRequest monitor,
IRunControl.RunControlContext ctx, Runnable done) {
- super(model, ctx.getID());
+ super(model.getLaunch(), ctx);
this.monitor = monitor;
- this.ctx = ctx;
this.done = done;
+ node = (TCFNodeExecContext)model.getNode(context_id);
}
- public void run() {
- assert !exited;
- if (!started) {
- started = true;
- rc.addListener(this);
- node = (TCFNodeExecContext)model.getNode(ctx.getID());
- if (node == null) {
- exit(new Exception("Invalid context ID"));
- return;
- }
- if (!ctx.canResume(IRunControl.RM_STEP_OUT)) {
- model.invokeLater(TIMEOUT, new Runnable() {
- public void run() {
- exit(new Exception("Time out"));
- }
- });
- }
- }
- if (!node.validateNode(this)) return;
- if (!node.isSuspended()) {
- exit(new Exception("Context is not suspended"));
- return;
- }
- if (ctx.canResume(IRunControl.RM_STEP_OUT)) {
- if (step_cnt > 0) return;
- ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- exit(error);
- }
- });
- step_cnt++;
- return;
- }
- if (frame == null) {
- frame = node.getTopFrame();
- if (frame == null) {
- exit(new Exception("Cannot get top stack frame"));
- return;
- }
- }
- if (!frame.validateNode(this)) return;
- if (frame.getFrameNo() < 0) {
- // Stepped out of selected function
- exit(null);
- }
- else if (bps != null && ctx.canResume(IRunControl.RM_RESUME)) {
- if (bp == null) {
- BigInteger addr = frame.getReturnAddress();
- if (addr == null) {
- exit(new Exception("Unknown stack frame return address"));
- return;
- }
- bp = new HashMap<String,Object>();
- bp.put(IBreakpoints.PROP_ID, "Step" + System.currentTimeMillis());
- bp.put(IBreakpoints.PROP_LOCATION, addr.toString());
- bp.put(IBreakpoints.PROP_CONDITION, "$thread==\"" + ctx.getID() + "\"");
- bp.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
- bps.add(bp, new IBreakpoints.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- }
- ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error != null) exit(error);
- }
- });
- }
- else {
- exit(new Exception("Step out is not supported"));
- }
- }
-
- private void exit(Throwable error) {
- assert started;
- if (exited) return;
- if (bp != null) {
- bps.remove(new String[]{ (String)bp.get(IBreakpoints.PROP_ID) }, new IBreakpoints.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- }
- });
- }
- rc.removeListener(this);
- exited = true;
- if (error != null) {
- monitor.setStatus(new Status(IStatus.ERROR,
- Activator.PLUGIN_ID, IStatus.OK, "Cannot step", error));
- }
- done.run();
- done();
+ @Override
+ protected TCFDataCache<TCFContextState> getContextState() {
+ if (node == null) return null;
+ return node.getState();
}
- public void containerResumed(String[] context_ids) {
+ @Override
+ protected TCFDataCache<StackTraceContext> getStackFrame() {
+ if (frame == null) frame = node.getTopFrame();
+ if (frame == null) return null;
+ return frame.getStackTraceContext();
}
- public void containerSuspended(String context, String pc,
- String reason, Map<String, Object> params,
- String[] suspended_ids) {
- for (String id : suspended_ids) {
- if (!id.equals(context)) contextSuspended(id, null, null, null);
- }
- contextSuspended(context, pc, reason, params);
+ @Override
+ protected int getStackFrameIndex() {
+ if (frame == null) frame = node.getTopFrame();
+ if (frame == null) return 0;
+ return frame.getFrameNo();
}
- public void contextAdded(RunControlContext[] contexts) {
- }
-
- public void contextChanged(RunControlContext[] contexts) {
- for (RunControlContext c : contexts) {
- if (c.getID().equals(ctx.getID())) ctx = c;
- }
+ @Override
+ protected TCFDataCache<?> getStackTrace() {
+ return node.getStackTrace();
}
-
- public void contextException(String context, String msg) {
- if (context.equals(ctx.getID())) exit(new Exception(msg));
- }
-
- public void contextRemoved(String[] context_ids) {
- for (String context : context_ids) {
- if (context.equals(ctx.getID())) exit(null);
+
+ @Override
+ protected void exit(Throwable error) {
+ if (exited) return;
+ super.exit(error);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ Activator.PLUGIN_ID, IStatus.OK, "Cannot step", error));
}
- }
-
- public void contextResumed(String context) {
- }
-
- public void contextSuspended(String context, String pc, String reason,
- Map<String, Object> params) {
- if (!context.equals(ctx.getID())) return;
- exit(null);
+ done.run();
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
index d44e61ef6..dc38b51cc 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
@@ -135,6 +135,12 @@ public class TCFAnnotationManager {
}
updateActiveLaunch();
}
+
+ public void onContextActionsDone(TCFLaunch launch) {
+ }
+
+ public void onContextActionsStart(TCFLaunch launch) {
+ }
};
private final ISelectionListener selection_listener = new ISelectionListener() {
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
index 8f69833cc..d3fb608f2 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
@@ -12,9 +12,7 @@ package org.eclipse.tm.internal.tcf.debug.ui.model;
import java.util.Collection;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.Map;
-import java.util.TreeSet;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
@@ -54,6 +52,7 @@ import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
import org.eclipse.tm.internal.tcf.debug.ui.Activator;
import org.eclipse.tm.internal.tcf.debug.ui.commands.DisconnectCommand;
import org.eclipse.tm.internal.tcf.debug.ui.commands.ResumeCommand;
@@ -77,7 +76,11 @@ import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
-
+/**
+ * TCFModel represents remote target state as it is known to host.
+ * The main job of the model is caching remote data,
+ * keeping the cache in a coherent state, and feeding UI with up-to-date data.
+ */
public class TCFModel implements IElementContentProvider, IElementLabelProvider,
IModelProxyFactory, IColumnPresentationFactory, ISourceDisplay {
@@ -88,7 +91,6 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
private final Map<String,TCFNode> id2node = new HashMap<String,TCFNode>();
@SuppressWarnings("unchecked")
private final Map<Class,Object> commands = new HashMap<Class,Object>();
- private final TreeSet<FutureTask> future_task_queue = new TreeSet<FutureTask>();
private static final Map<ILaunchConfiguration,IEditorInput> editor_not_found =
new HashMap<ILaunchConfiguration,IEditorInput>();
@@ -96,101 +98,8 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
private TCFNodeLaunch launch_node;
private boolean disposed;
- private int future_task_cnt;
-
private static int debug_view_selection_cnt;
private static int display_source_cnt;
-
- private int context_action_cnt;
- private final HashMap<String,LinkedList<Runnable>> context_action_queue =
- new HashMap<String,LinkedList<Runnable>>();
-
- public static abstract class ContextAction implements Runnable {
-
- protected final TCFModel model;
- protected final String context_id;
-
- public ContextAction(TCFModel model, String context_id) {
- assert Protocol.isDispatchThread();
- assert context_id != null;
- this.model = model;
- this.context_id = context_id;
- LinkedList<Runnable> l = model.context_action_queue.get(context_id);
- if (l == null) {
- l = new LinkedList<Runnable>();
- model.context_action_queue.put(context_id, l);
- }
- l.add(this);
- if (l.getFirst() == this) Protocol.invokeLater(this);
- model.context_action_cnt++;
- }
-
- protected void done() {
- assert Protocol.isDispatchThread();
- model.context_action_cnt--;
- LinkedList<Runnable> l = model.context_action_queue.get(context_id);
- if (l == null) return; // context exited
- assert l.getFirst() == this;
- l.removeFirst();
- if (!l.isEmpty()) {
- assert model.context_action_cnt > 0;
- Protocol.invokeLater(l.getFirst());
- }
- else if (model.context_action_cnt == 0) {
- model.fireModelChanged();
- }
- }
- }
-
- private static class FutureTask implements Comparable<FutureTask>{
- final int id;
- final long time;
- final Runnable run;
-
- FutureTask(int id, long time, Runnable run) {
- this.id = id;
- this.time = time;
- this.run = run;
- }
-
- public int compareTo(FutureTask x) {
- if (x == this) return 0;
- if (time < x.time) return -1;
- if (time > x.time) return +1;
- if (id < x.id) return -1;
- if (id > x.id) return +1;
- assert false;
- return 0;
- }
- }
-
- private final Thread future_task_dispatcher = new Thread() {
- public void run() {
- try {
- synchronized (future_task_queue) {
- while (!disposed) {
- if (future_task_queue.isEmpty()) {
- future_task_queue.wait();
- }
- else {
- long time = System.currentTimeMillis();
- FutureTask t = future_task_queue.first();
- if (t.time > time) {
- future_task_queue.wait(t.time - time);
- }
- else {
- future_task_queue.remove(t);
- Protocol.invokeLater(t.run);
- }
- }
- }
- }
- }
- catch (Throwable x) {
- x.printStackTrace();
- }
- }
- };
private final IMemory.MemoryListener mem_listener = new IMemory.MemoryListener() {
@@ -357,8 +266,6 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
commands.put(IStepIntoHandler.class, new StepIntoCommand(this));
commands.put(IStepOverHandler.class, new StepOverCommand(this));
commands.put(IStepReturnHandler.class, new StepReturnCommand(this));
- future_task_dispatcher.setName("TCF Future Task Dispatcher");
- future_task_dispatcher.start();
}
@SuppressWarnings("unchecked")
@@ -390,6 +297,13 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
assert id2node.size() == 0;
}
+
+ void onContextActionsStart() {
+ }
+
+ void onContextActionsDone() {
+ fireModelChanged();
+ }
void onProxyInstalled(final TCFModelProxy p) {
Protocol.invokeAndWait(new Runnable() {
@@ -410,7 +324,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
private void onContextRemoved(final String[] context_ids) {
boolean close_channel = false;
for (String id : context_ids) {
- context_action_queue.remove(id);
+ launch.removeContextActions(id);
TCFNode node = getNode(id);
if (node instanceof TCFNodeExecContext) {
((TCFNodeExecContext)node).onContextRemoved();
@@ -451,16 +365,6 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
void dispose() {
- synchronized (future_task_queue) {
- disposed = true;
- future_task_queue.notify();
- }
- try {
- future_task_dispatcher.join();
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
}
void addNode(String id, TCFNode node) {
@@ -479,7 +383,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
void fireModelChanged() {
assert Protocol.isDispatchThread();
- if (context_action_cnt > 0) return;
+ if (launch.hasPendingContextActions()) return;
for (TCFModelProxy p : model_proxies.values()) p.fireModelChanged();
}
@@ -502,13 +406,6 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
return id2node.get(id);
}
- public void invokeLater(long delay, Runnable run) {
- synchronized (future_task_queue) {
- future_task_queue.add(new FutureTask(future_task_cnt++, System.currentTimeMillis() + delay, run));
- future_task_queue.notify();
- }
- }
-
public void update(IChildrenCountUpdate[] updates) {
for (int i = 0; i < updates.length; i++) {
Object o = updates[i].getElement();
@@ -599,7 +496,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
final IDebugView view = (IDebugView)window.getActivePage().findView(IDebugUIConstants.ID_DEBUG_VIEW);
if (view == null) return;
if (!((AbstractDebugView)view).isAvailable()) return;
- invokeLater(300, new Runnable() {
+ Protocol.invokeLater(300, new Runnable() {
public void run() {
TCFNode node = getNode(node_id);
if (node == null) return;
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
index 2491fa900..cbbbebfc3 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
@@ -38,6 +38,16 @@ public class TCFModelManager {
TCFModel model = models.get(launch);
if (model != null) model.onDisconnected();
}
+
+ public void onContextActionsDone(TCFLaunch launch) {
+ TCFModel model = models.get(launch);
+ if (model != null) model.onContextActionsDone();
+ }
+
+ public void onContextActionsStart(TCFLaunch launch) {
+ TCFModel model = models.get(launch);
+ if (model != null) model.onContextActionsStart();
+ }
};
private final ILaunchesListener debug_launch_listener = new ILaunchesListener() {
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
index 8ec20b19e..503db2851 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
@@ -22,6 +22,8 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.swt.graphics.RGB;
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
@@ -40,17 +42,10 @@ public class TCFNodeExecContext extends TCFNode {
private final TCFDataCache<IMemory.MemoryContext> mem_context;
private final TCFDataCache<IRunControl.RunControlContext> run_context;
- private final TCFDataCache<ContextState> state;
+ private final TCFDataCache<TCFContextState> state;
private final Map<BigInteger,TCFSourceRef> line_info_cache;
- private static class ContextState {
- boolean suspended;
- String suspended_pc;
- String suspended_reason;
- boolean terminated;
- }
-
private int resumed_cnt;
TCFNodeExecContext(TCFNode parent, final String id) {
@@ -99,7 +94,7 @@ public class TCFNodeExecContext extends TCFNode {
return false;
}
};
- state = new TCFDataCache<ContextState>(channel) {
+ state = new TCFDataCache<TCFContextState>(channel) {
@Override
protected boolean startDataRetrieval() {
assert command == null;
@@ -114,10 +109,11 @@ public class TCFNodeExecContext extends TCFNode {
}
command = ctx.getState(new IRunControl.DoneGetState() {
public void doneGetState(IToken token, Exception error, boolean suspended, String pc, String reason, Map<String,Object> params) {
- ContextState s = new ContextState();
- s.suspended = suspended;
- s.suspended_pc = pc;
- s.suspended_reason = reason;
+ TCFContextState s = new TCFContextState();
+ s.is_suspended = suspended;
+ s.suspend_pc = pc;
+ s.suspend_reason = reason;
+ s.suspend_params = params;
set(token, error, s);
}
});
@@ -174,8 +170,8 @@ public class TCFNodeExecContext extends TCFNode {
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx == null || !ctx.hasState()) return false;
if (!state.isValid()) return false;
- ContextState s = state.getData();
- return s != null && !s.suspended;
+ TCFContextState s = state.getData();
+ return s != null && !s.is_suspended;
}
@Override
@@ -185,8 +181,8 @@ public class TCFNodeExecContext extends TCFNode {
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx == null || !ctx.hasState()) return false;
if (!state.isValid()) return false;
- ContextState s = state.getData();
- return s != null && s.suspended;
+ TCFContextState s = state.getData();
+ return s != null && s.is_suspended;
}
@Override
@@ -196,10 +192,10 @@ public class TCFNodeExecContext extends TCFNode {
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx == null || !ctx.hasState()) return null;
if (!state.isValid()) return null;
- ContextState s = state.getData();
+ TCFContextState s = state.getData();
if (s == null) return null;
- if (s.suspended_pc == null) return null;
- return new BigInteger(s.suspended_pc);
+ if (s.suspend_pc == null) return null;
+ return new BigInteger(s.suspend_pc);
}
public TCFNodeStackFrame getTopFrame() {
@@ -207,6 +203,14 @@ public class TCFNodeExecContext extends TCFNode {
if (!children_stack.isValid()) return null;
return children_stack.getTopFrame();
}
+
+ public TCFDataCache<TCFContextState> getState() {
+ return state;
+ }
+
+ public TCFChildrenStackTrace getStackTrace() {
+ return children_stack;
+ }
@Override
protected void getData(IChildrenCountUpdate result) {
@@ -283,7 +287,7 @@ public class TCFNodeExecContext extends TCFNode {
label += " (Running)";
}
else if (isSuspended()) {
- String r = state.getData().suspended_reason;
+ String r = state.getData().suspend_reason;
if (r != null) {
label += " (" + r + ")";
}
@@ -354,10 +358,11 @@ public class TCFNodeExecContext extends TCFNode {
void onContextSuspended(String pc, String reason, Map<String,Object> params) {
assert !disposed;
- ContextState s = new ContextState();
- s.suspended = true;
- s.suspended_pc = pc;
- s.suspended_reason = reason;
+ TCFContextState s = new TCFContextState();
+ s.is_suspended = true;
+ s.suspend_pc = pc;
+ s.suspend_reason = reason;
+ s.suspend_params = params;
state.reset(s);
children_stack.onSuspended();
children_regs.onSuspended();
@@ -367,10 +372,10 @@ public class TCFNodeExecContext extends TCFNode {
void onContextResumed() {
assert !disposed;
- state.reset(new ContextState());
+ state.reset(new TCFContextState());
addModelDelta(IModelDelta.STATE);
final int cnt = ++resumed_cnt;
- model.invokeLater(250, new Runnable() {
+ Protocol.invokeLater(250, new Runnable() {
public void run() {
if (cnt != resumed_cnt) return;
if (disposed) return;
@@ -504,9 +509,9 @@ public class TCFNodeExecContext extends TCFNode {
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && ctx.hasState()) {
// Thread
- ContextState s = state.getData();
- if (s != null && s.terminated) return ImageCache.IMG_THREAD_TERMINATED;
- if (s != null && s.suspended) return ImageCache.IMG_THREAD_SUSPENDED;
+ TCFContextState s = state.getData();
+ if (s != null && s.is_terminated) return ImageCache.IMG_THREAD_TERMINATED;
+ if (s != null && s.is_suspended) return ImageCache.IMG_THREAD_SUSPENDED;
return ImageCache.IMG_THREAD_RUNNNIG;
}
else if (ctx != null) {
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
index 141b8ad4d..0c1af3b69 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
@@ -21,6 +21,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.swt.graphics.RGB;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
@@ -146,6 +147,10 @@ public class TCFNodeStackFrame extends TCFNode {
public IMemory.MemoryContext getMemoryContext() {
return parent.getMemoryContext();
}
+
+ public TCFDataCache<IStackTrace.StackTraceContext> getStackTraceContext() {
+ return stack_trace_context;
+ }
@Override
public boolean isRunning() {
diff --git a/plugins/org.eclipse.tm.tcf.debug/META-INF/MANIFEST.MF b/plugins/org.eclipse.tm.tcf.debug/META-INF/MANIFEST.MF
index b1525cfdb..d780b695d 100644
--- a/plugins/org.eclipse.tm.tcf.debug/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.tm.tcf.debug/META-INF/MANIFEST.MF
@@ -13,4 +13,5 @@ Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy
Eclipse-LazyStart: true
Export-Package: org.eclipse.tm.internal.tcf.debug.launch,
+ org.eclipse.tm.internal.tcf.debug.actions,
org.eclipse.tm.internal.tcf.debug.model
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFAction.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFAction.java
new file mode 100644
index 000000000..7e298146f
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFAction.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.debug.actions;
+
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.tcf.protocol.Protocol;
+
+/**
+ * TCFAction class represents user request to perform some action(s) on
+ * a remote context, for example, step over line command.
+ * Such action might require multiple data exchanges with remote target.
+ * Actions for a particular context should be executed sequentially -
+ * it does not make sense to execute two step commands concurrently.
+ * If user requests actions faster then they are executed,
+ * actions are placed into a FIFO queue.
+ *
+ * Clients are expected to implement run() method to perform the action job.
+ * When the job is done, client code should call done() method.
+ */
+public abstract class TCFAction implements Runnable {
+
+ protected final TCFLaunch launch;
+ protected final String context_id;
+
+ public TCFAction(TCFLaunch launch, String context_id) {
+ assert Protocol.isDispatchThread();
+ assert context_id != null;
+ this.launch = launch;
+ this.context_id = context_id;
+ launch.addContextAction(this, context_id);
+ }
+
+ protected void done() {
+ assert Protocol.isDispatchThread();
+ launch.removeContextAction(this, context_id);
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepInto.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepInto.java
new file mode 100644
index 000000000..b2595ae0b
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepInto.java
@@ -0,0 +1,224 @@
+package org.eclipse.tm.internal.tcf.debug.actions;
+
+import java.math.BigInteger;
+import java.util.Map;
+
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.ILineNumbers;
+import org.eclipse.tm.tcf.services.IRunControl;
+import org.eclipse.tm.tcf.services.IStackTrace;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
+
+public abstract class TCFActionStepInto extends TCFAction implements IRunControl.RunControlListener {
+
+ private static final long TIMEOUT = 10000;
+
+ private final boolean src_step;
+ private final IRunControl rc = launch.getService(IRunControl.class);
+
+ private IRunControl.RunControlContext ctx;
+ private TCFDataCache<TCFContextState> state;
+ private TCFDataCache<TCFSourceRef> line_info;
+ private TCFSourceRef source_ref;
+ private BigInteger pc0;
+ private BigInteger pc1;
+ private int step_cnt;
+
+ protected boolean exited;
+
+ public TCFActionStepInto(TCFLaunch launch, IRunControl.RunControlContext ctx, boolean src_step) {
+ super(launch, ctx.getID());
+ this.ctx = ctx;
+ this.src_step = src_step;
+ }
+
+ protected abstract TCFDataCache<TCFContextState> getContextState();
+ protected abstract TCFDataCache<TCFSourceRef> getLineInfo();
+ protected abstract TCFDataCache<?> getStackTrace();
+ protected abstract TCFDataCache<IStackTrace.StackTraceContext> getStackFrame();
+ protected abstract int getStackFrameIndex();
+
+ public void run() {
+ if (exited) return;
+ if (state == null) {
+ rc.addListener(this);
+ state = getContextState();
+ if (state == null) {
+ exit(new Exception("Invalid context ID"));
+ return;
+ }
+ if (!ctx.canResume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO)) {
+ Protocol.invokeLater(TIMEOUT, new Runnable() {
+ public void run() {
+ exit(new Exception("Time out"));
+ }
+ });
+ }
+ }
+ if (!state.validate()) {
+ state.wait(this);
+ return;
+ }
+ if (!state.getData().is_suspended) {
+ exit(new Exception("Context is not suspended"));
+ return;
+ }
+ if (ctx.canResume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO)) {
+ if (step_cnt > 0) return;
+ ctx.resume(src_step ? IRunControl.RM_STEP_INTO_LINE : IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ exit(error);
+ }
+ });
+ step_cnt++;
+ return;
+ }
+ if (!src_step) {
+ exit(new Exception("Step into is not supported"));
+ return;
+ }
+ TCFDataCache<?> stack_trace = getStackTrace();
+ if (!stack_trace.validate()) {
+ stack_trace.wait(this);
+ return;
+ }
+ if (source_ref == null) {
+ line_info = getLineInfo();
+ if (!line_info.validate()) {
+ line_info.wait(this);
+ return;
+ }
+ source_ref = line_info.getData();
+ if (source_ref == null) {
+ exit(new Exception("Line info not available"));
+ return;
+ }
+ if (source_ref.error != null) {
+ exit(source_ref.error);
+ return;
+ }
+ ILineNumbers.CodeArea area = source_ref.area;
+ if (area != null) {
+ if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
+ else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
+ if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
+ else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
+ }
+ }
+ if (getStackFrameIndex() != 0) {
+ // Stepped out of selected function
+ exit(null);
+ return;
+ }
+ if (step_cnt > 0) {
+ TCFDataCache<IStackTrace.StackTraceContext> frame = getStackFrame();
+ if (!frame.validate()) {
+ frame.wait(this);
+ return;
+ }
+ Number addr = frame.getData().getInstructionAddress();
+ BigInteger pc = addr instanceof BigInteger ? (BigInteger)addr : new BigInteger(addr.toString());
+ if (pc == null || pc0 == null || pc1 == null) {
+ exit(null);
+ return;
+ }
+ if (pc.compareTo(pc0) < 0 || pc.compareTo(pc1) >= 0) {
+ if (!line_info.validate()) {
+ line_info.wait(this);
+ return;
+ }
+ TCFSourceRef ref = line_info.getData();
+ if (ref != null && ref.area != null) {
+ if (isSameLine(source_ref.area, ref.area)) {
+ source_ref = ref;
+ ILineNumbers.CodeArea area = source_ref.area;
+ if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
+ else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
+ if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
+ else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
+ }
+ else {
+ exit(null);
+ return;
+ }
+ }
+ }
+ }
+ step_cnt++;
+ if (ctx.canResume(IRunControl.RM_STEP_INTO)) {
+ ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else {
+ exit(new Exception("Step into is not supported"));
+ }
+ }
+
+ private boolean isSameLine(ILineNumbers.CodeArea x, ILineNumbers.CodeArea y) {
+ if (x == null || y == null) return false;
+ if (x.start_line != y.start_line) return false;
+ if (x.directory != y.directory && (x.directory == null || !x.directory.equals(y.directory))) return false;
+ if (x.file != y.file && (x.file == null || !x.file.equals(y.file))) return false;
+ return true;
+ }
+
+ protected void exit(Throwable error) {
+ if (exited) return;
+ rc.removeListener(this);
+ exited = true;
+ done();
+ }
+
+ public void containerResumed(String[] context_ids) {
+ }
+
+ public void containerSuspended(String context, String pc,
+ String reason, Map<String, Object> params,
+ String[] suspended_ids) {
+ for (String id : suspended_ids) {
+ if (!id.equals(context)) contextSuspended(id, null, null, null);
+ }
+ contextSuspended(context, pc, reason, params);
+ }
+
+ public void contextAdded(RunControlContext[] contexts) {
+ }
+
+ public void contextChanged(RunControlContext[] contexts) {
+ for (RunControlContext c : contexts) {
+ if (c.getID().equals(ctx.getID())) ctx = c;
+ }
+ }
+
+ public void contextException(String context, String msg) {
+ if (context.equals(ctx.getID())) exit(new Exception(msg));
+ }
+
+ public void contextRemoved(String[] context_ids) {
+ for (String context : context_ids) {
+ if (context.equals(ctx.getID())) exit(null);
+ }
+ }
+
+ public void contextResumed(String context) {
+ }
+
+ public void contextSuspended(String context, String pc, String reason,
+ Map<String, Object> params) {
+ if (!context.equals(ctx.getID())) return;
+ if (IRunControl.REASON_STEP.equals(reason)) {
+ Protocol.invokeLater(this);
+ }
+ else {
+ exit(null);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOut.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOut.java
new file mode 100644
index 000000000..b6e64a286
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOut.java
@@ -0,0 +1,170 @@
+package org.eclipse.tm.internal.tcf.debug.actions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IBreakpoints;
+import org.eclipse.tm.tcf.services.IRunControl;
+import org.eclipse.tm.tcf.services.IStackTrace;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
+
+public abstract class TCFActionStepOut extends TCFAction implements IRunControl.RunControlListener {
+
+ private static final long TIMEOUT = 10000;
+
+ private final IRunControl rc = launch.getService(IRunControl.class);
+ private final IBreakpoints bps = launch.getService(IBreakpoints.class);
+
+ private IRunControl.RunControlContext ctx;
+ private TCFDataCache<TCFContextState> state;
+ private int step_cnt;
+ private Map<String,Object> bp;
+
+ protected boolean exited;
+
+ public TCFActionStepOut(TCFLaunch launch, IRunControl.RunControlContext ctx) {
+ super(launch, ctx.getID());
+ this.ctx = ctx;
+ }
+
+ protected abstract TCFDataCache<TCFContextState> getContextState();
+ protected abstract TCFDataCache<?> getStackTrace();
+ protected abstract TCFDataCache<IStackTrace.StackTraceContext> getStackFrame();
+ protected abstract int getStackFrameIndex();
+
+ public void run() {
+ if (exited) return;
+ if (state == null) {
+ rc.addListener(this);
+ state = getContextState();
+ if (state == null) {
+ exit(new Exception("Invalid context ID"));
+ return;
+ }
+ if (!ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ Protocol.invokeLater(TIMEOUT, new Runnable() {
+ public void run() {
+ exit(new Exception("Time out"));
+ }
+ });
+ }
+ }
+ if (!state.validate()) {
+ state.wait(this);
+ return;
+ }
+ if (!state.getData().is_suspended) {
+ exit(new Exception("Context is not suspended"));
+ return;
+ }
+ if (ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ if (step_cnt > 0) return;
+ ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ exit(error);
+ }
+ });
+ step_cnt++;
+ return;
+ }
+ TCFDataCache<?> stack_trace = getStackTrace();
+ if (!stack_trace.validate()) {
+ stack_trace.wait(this);
+ return;
+ }
+ if (getStackFrameIndex() < 0) {
+ // Stepped out of selected function
+ exit(null);
+ }
+ else if (bps != null && ctx.canResume(IRunControl.RM_RESUME)) {
+ if (bp == null) {
+ TCFDataCache<IStackTrace.StackTraceContext> frame = getStackFrame();
+ if (!frame.validate()) {
+ frame.wait(this);
+ return;
+ }
+ Number addr = frame.getData().getReturnAddress();
+ if (addr == null) {
+ exit(new Exception("Unknown stack frame return address"));
+ return;
+ }
+ bp = new HashMap<String,Object>();
+ bp.put(IBreakpoints.PROP_ID, "Step" + System.currentTimeMillis());
+ bp.put(IBreakpoints.PROP_LOCATION, addr.toString());
+ bp.put(IBreakpoints.PROP_CONDITION, "$thread==\"" + ctx.getID() + "\"");
+ bp.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
+ bps.add(bp, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else {
+ exit(new Exception("Step out is not supported"));
+ }
+ }
+
+ protected void exit(Throwable error) {
+ if (exited) return;
+ if (bp != null) {
+ bps.remove(new String[]{ (String)bp.get(IBreakpoints.PROP_ID) }, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ }
+ });
+ }
+ rc.removeListener(this);
+ exited = true;
+ done();
+ }
+
+ public void containerResumed(String[] context_ids) {
+ }
+
+ public void containerSuspended(String context, String pc,
+ String reason, Map<String, Object> params,
+ String[] suspended_ids) {
+ for (String id : suspended_ids) {
+ if (!id.equals(context)) contextSuspended(id, null, null, null);
+ }
+ contextSuspended(context, pc, reason, params);
+ }
+
+ public void contextAdded(RunControlContext[] contexts) {
+ }
+
+ public void contextChanged(RunControlContext[] contexts) {
+ for (RunControlContext c : contexts) {
+ if (c.getID().equals(ctx.getID())) ctx = c;
+ }
+ }
+
+ public void contextException(String context, String msg) {
+ if (context.equals(ctx.getID())) exit(new Exception(msg));
+ }
+
+ public void contextRemoved(String[] context_ids) {
+ for (String context : context_ids) {
+ if (context.equals(ctx.getID())) exit(null);
+ }
+ }
+
+ public void contextResumed(String context) {
+ }
+
+ public void contextSuspended(String context, String pc, String reason,
+ Map<String, Object> params) {
+ if (!context.equals(ctx.getID())) return;
+ exit(null);
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOver.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOver.java
new file mode 100644
index 000000000..f262faa2b
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/actions/TCFActionStepOver.java
@@ -0,0 +1,290 @@
+package org.eclipse.tm.internal.tcf.debug.actions;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IBreakpoints;
+import org.eclipse.tm.tcf.services.ILineNumbers;
+import org.eclipse.tm.tcf.services.IRunControl;
+import org.eclipse.tm.tcf.services.IStackTrace;
+import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.util.TCFDataCache;
+
+public abstract class TCFActionStepOver extends TCFAction implements IRunControl.RunControlListener {
+
+ private static final long TIMEOUT = 10000;
+
+ private final boolean src_step;
+ private final IRunControl rc = launch.getService(IRunControl.class);
+ private final IBreakpoints bps = launch.getService(IBreakpoints.class);
+
+ private IRunControl.RunControlContext ctx;
+ private TCFDataCache<TCFContextState> state;
+ private TCFDataCache<TCFSourceRef> line_info;
+ private TCFSourceRef source_ref;
+ private BigInteger pc0;
+ private BigInteger pc1;
+ private int step_cnt;
+ private Map<String,Object> bp;
+
+ protected boolean exited;
+
+ public TCFActionStepOver(TCFLaunch launch, IRunControl.RunControlContext ctx, boolean src_step) {
+ super(launch, ctx.getID());
+ this.ctx = ctx;
+ this.src_step = src_step;
+ }
+
+ protected abstract TCFDataCache<TCFContextState> getContextState();
+ protected abstract TCFDataCache<TCFSourceRef> getLineInfo();
+ protected abstract TCFDataCache<?> getStackTrace();
+ protected abstract TCFDataCache<IStackTrace.StackTraceContext> getStackFrame();
+ protected abstract int getStackFrameIndex();
+
+ public void run() {
+ if (exited) return;
+ if (state == null) {
+ rc.addListener(this);
+ state = getContextState();
+ if (state == null) {
+ exit(new Exception("Invalid context ID"));
+ return;
+ }
+ if (!ctx.canResume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER)) {
+ Protocol.invokeLater(TIMEOUT, new Runnable() {
+ public void run() {
+ exit(new Exception("Time out"));
+ }
+ });
+ }
+ }
+ if (!state.validate()) {
+ state.wait(this);
+ return;
+ }
+ if (!state.getData().is_suspended) {
+ exit(new Exception("Context is not suspended"));
+ return;
+ }
+ if (ctx.canResume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER)) {
+ if (step_cnt > 0) return;
+ ctx.resume(src_step ? IRunControl.RM_STEP_OVER_LINE : IRunControl.RM_STEP_OVER, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ exit(error);
+ }
+ });
+ step_cnt++;
+ return;
+ }
+ TCFDataCache<?> stack_trace = getStackTrace();
+ if (!stack_trace.validate()) {
+ stack_trace.wait(this);
+ return;
+ }
+ if (src_step && source_ref == null) {
+ line_info = getLineInfo();
+ if (!line_info.validate()) {
+ line_info.wait(this);
+ return;
+ }
+ source_ref = line_info.getData();
+ if (source_ref == null) {
+ exit(new Exception("Line info not available"));
+ return;
+ }
+ if (source_ref.error != null) {
+ exit(source_ref.error);
+ return;
+ }
+ ILineNumbers.CodeArea area = source_ref.area;
+ if (area != null) {
+ if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
+ else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
+ if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
+ else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
+ }
+ }
+ if (getStackFrameIndex() != 0) {
+ if (getStackFrameIndex() < 0) {
+ // Stepped out of selected function
+ exit(null);
+ }
+ else if (ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else if (bps != null && ctx.canResume(IRunControl.RM_RESUME)) {
+ if (bp == null) {
+ TCFDataCache<IStackTrace.StackTraceContext> frame = getStackFrame();
+ if (!frame.validate()) {
+ frame.wait(this);
+ return;
+ }
+ Number addr = frame.getData().getInstructionAddress();
+ if (addr == null) {
+ exit(new Exception("Unknown PC address"));
+ return;
+ }
+ bp = new HashMap<String,Object>();
+ bp.put(IBreakpoints.PROP_ID, "Step" + System.currentTimeMillis());
+ bp.put(IBreakpoints.PROP_LOCATION, addr.toString());
+ bp.put(IBreakpoints.PROP_CONDITION, "$thread==\"" + ctx.getID() + "\"");
+ bp.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
+ bps.add(bp, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else {
+ exit(new Exception("Step over is not supported"));
+ }
+ return;
+ }
+ if (bp != null) {
+ bps.remove(new String[]{ (String)bp.get(IBreakpoints.PROP_ID) }, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ bp = null;
+ }
+ if (step_cnt > 0) {
+ if (pc0 == null || pc1 == null || state.getData().suspend_pc == null) {
+ exit(null);
+ return;
+ }
+ assert src_step;
+ BigInteger pc = new BigInteger(state.getData().suspend_pc);
+ if (pc.compareTo(pc0) < 0 || pc.compareTo(pc1) >= 0) {
+ if (!line_info.validate()) {
+ line_info.wait(this);
+ return;
+ }
+ TCFSourceRef ref = line_info.getData();
+ if (ref != null && ref.area != null) {
+ if (isSameLine(source_ref.area, ref.area)) {
+ source_ref = ref;
+ ILineNumbers.CodeArea area = source_ref.area;
+ if (area.start_address instanceof BigInteger) pc0 = (BigInteger)area.start_address;
+ else if (area.start_address != null) pc0 = new BigInteger(area.start_address.toString());
+ if (area.end_address instanceof BigInteger) pc1 = (BigInteger)area.end_address;
+ else if (area.end_address != null) pc1 = new BigInteger(area.end_address.toString());
+ }
+ else {
+ exit(null);
+ return;
+ }
+ }
+ }
+ }
+ step_cnt++;
+ if (ctx.canResume(IRunControl.RM_STEP_OVER)) {
+ ctx.resume(IRunControl.RM_STEP_OVER, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else if (ctx.canResume(IRunControl.RM_STEP_INTO)) {
+ ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ }
+ else {
+ exit(new Exception("Step over is not supported"));
+ }
+ }
+
+ protected void exit(Throwable error) {
+ if (exited) return;
+ if (bp != null) {
+ bps.remove(new String[]{ (String)bp.get(IBreakpoints.PROP_ID) }, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ }
+ });
+ }
+ rc.removeListener(this);
+ exited = true;
+ done();
+ }
+
+ public void containerResumed(String[] context_ids) {
+ }
+
+ public void containerSuspended(String context, String pc,
+ String reason, Map<String, Object> params,
+ String[] suspended_ids) {
+ for (String id : suspended_ids) {
+ if (!id.equals(context)) contextSuspended(id, null, null, null);
+ }
+ contextSuspended(context, pc, reason, params);
+ }
+
+ public void contextAdded(RunControlContext[] contexts) {
+ }
+
+ public void contextChanged(RunControlContext[] contexts) {
+ for (RunControlContext c : contexts) {
+ if (c.getID().equals(ctx.getID())) ctx = c;
+ }
+ }
+
+ public void contextException(String context, String msg) {
+ if (context.equals(ctx.getID())) exit(new Exception(msg));
+ }
+
+ public void contextRemoved(String[] context_ids) {
+ for (String context : context_ids) {
+ if (context.equals(ctx.getID())) exit(null);
+ }
+ }
+
+ public void contextResumed(String context) {
+ }
+
+ public void contextSuspended(String context, String pc, String reason,
+ Map<String, Object> params) {
+ if (!context.equals(ctx.getID())) return;
+ if (IRunControl.REASON_STEP.equals(reason) || isMyBreakpoint(pc, reason)) {
+ Protocol.invokeLater(this);
+ }
+ else {
+ exit(null);
+ }
+ }
+
+ private boolean isSameLine(ILineNumbers.CodeArea x, ILineNumbers.CodeArea y) {
+ if (x == null || y == null) return false;
+ if (x.start_line != y.start_line) return false;
+ if (x.directory != y.directory && (x.directory == null || !x.directory.equals(y.directory))) return false;
+ if (x.file != y.file && (x.file == null || !x.file.equals(y.file))) return false;
+ return true;
+ }
+
+ private boolean isMyBreakpoint(String pc, String reason) {
+ if (bp == null) return false;
+ if (pc == null) return false;
+ if (!IRunControl.REASON_BREAKPOINT.equals(reason)) return false;
+ BigInteger x = new BigInteger(pc);
+ BigInteger y = new BigInteger((String)bp.get(IBreakpoints.PROP_LOCATION));
+ return x.equals(y);
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFContextState.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFContextState.java
new file mode 100644
index 000000000..3a9dd15a8
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFContextState.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.internal.tcf.debug.model;
+
+import java.util.Map;
+
+public class TCFContextState {
+ public boolean is_suspended;
+ public boolean is_terminated;
+
+ public String suspend_pc;
+ public String suspend_reason;
+ public Map<String,Object> suspend_params;
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
index f1c62b3ab..2a355d386 100644
--- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
@@ -14,6 +14,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -23,6 +24,7 @@ import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.Launch;
import org.eclipse.tm.internal.tcf.debug.Activator;
+import org.eclipse.tm.internal.tcf.debug.actions.TCFAction;
import org.eclipse.tm.internal.tcf.debug.launch.TCFLaunchDelegate;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IPeer;
@@ -41,6 +43,9 @@ public class TCFLaunch extends Launch {
public void onDisconnected(TCFLaunch launch);
+ public void onContextActionsStart(TCFLaunch launch);
+
+ public void onContextActionsDone(TCFLaunch launch);
}
private static final Collection<Listener> listeners = new ArrayList<Listener>();
@@ -55,6 +60,10 @@ public class TCFLaunch extends Launch {
private boolean last_context_exited;
private ProcessContext process;
+ private int context_action_cnt;
+ private final HashMap<String,LinkedList<Runnable>> context_action_queue =
+ new HashMap<String,LinkedList<Runnable>>();
+
public TCFLaunch(ILaunchConfiguration launchConfiguration, String mode) {
super(launchConfiguration, mode, null);
}
@@ -261,13 +270,18 @@ public class TCFLaunch extends Launch {
}
public void disconnect() throws DebugException {
- Protocol.invokeLater(new Runnable() {
- public void run() {
- if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
- channel.close();
+ try {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
+ channel.close();
+ }
}
- }
- });
+ });
+ }
+ catch (IllegalStateException x) {
+ disconnected = true;
+ }
}
public boolean canTerminate() {
@@ -307,4 +321,49 @@ public class TCFLaunch extends Launch {
});
assert channel.getState() == IChannel.STATE_OPENNING;
}
+
+ public void addContextAction(TCFAction action, String context_id) {
+ assert Protocol.isDispatchThread();
+ LinkedList<Runnable> list = context_action_queue.get(context_id);
+ if (list == null) {
+ list = new LinkedList<Runnable>();
+ context_action_queue.put(context_id, list);
+ }
+ list.add(action);
+ context_action_cnt++;
+ if (context_action_cnt == 1) {
+ for (Listener l : listeners) l.onContextActionsStart(this);
+ }
+ if (list.getFirst() == action) Protocol.invokeLater(action);
+ }
+
+ public void removeContextAction(TCFAction action, String context_id) {
+ assert Protocol.isDispatchThread();
+ LinkedList<Runnable> list = context_action_queue.get(context_id);
+ if (list == null) return;
+ assert list.getFirst() == action;
+ list.removeFirst();
+ context_action_cnt--;
+ if (!list.isEmpty()) {
+ assert context_action_cnt > 0;
+ Protocol.invokeLater(list.getFirst());
+ }
+ else if (context_action_cnt == 0) {
+ for (Listener l : listeners) l.onContextActionsDone(this);
+ }
+ }
+
+ public void removeContextActions(String context_id) {
+ assert Protocol.isDispatchThread();
+ LinkedList<Runnable> list = context_action_queue.remove(context_id);
+ if (list == null) return;
+ context_action_cnt -= list.size();
+ if (context_action_cnt == 0) {
+ for (Listener l : listeners) l.onContextActionsDone(this);
+ }
+ }
+
+ public boolean hasPendingContextActions() {
+ return context_action_cnt > 0;
+ }
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java
index 19cbdf74d..00405ed49 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java
@@ -8,7 +8,7 @@
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
-package org.eclipse.tm.internal.tcf.debug.ui.model;
+package org.eclipse.tm.internal.tcf.debug.model;
import java.math.BigInteger;
diff --git a/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/AdapterFactory.java b/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/AdapterFactory.java
index ff57c02e2..90e55420e 100644
--- a/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/AdapterFactory.java
+++ b/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/AdapterFactory.java
@@ -91,6 +91,7 @@ public class AdapterFactory implements IAdapterFactory, DsfSession.SessionEndedL
suspend_command = new DsfSuspendCommand(session);
resume_command = new DsfResumeCommand(session);
terminate_command = new TcfTerminateCommand(session);
+
//breakpoint_command = new BreakpointCommand();
//memory_retrieval = new DsfMemoryBlockRetrieval(ITCFConstants.ID_TCF_DEBUG_MODEL, );
session.registerModelAdapter(ISteppingModeTarget.class, steppin_mode_target);
diff --git a/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/ExecutableContextLayoutNode.java b/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/ExecutableContextLayoutNode.java
index acae2eca1..74bac79ba 100644
--- a/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/ExecutableContextLayoutNode.java
+++ b/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/ExecutableContextLayoutNode.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006 Ericsson and others.
+ * Copyright (c) 2006, 2008 Ericsson 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
@@ -12,11 +12,17 @@
package org.eclipse.tm.internal.tcf.dsf.ui.viewmodel;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.RejectedExecutionException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
+import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
@@ -32,12 +38,16 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProv
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.dsf.ui.Activator;
import org.eclipse.tm.internal.tcf.dsf.services.TCFDSFExecutionDMC;
import org.eclipse.tm.internal.tcf.dsf.services.TCFDSFRunControl;
-import org.eclipse.tm.internal.tcf.dsf.services.TCFDSFRunControlState;
+import org.eclipse.tm.internal.tcf.dsf.services.TCFDSFStack;
+import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.util.TCFDataCache;
@@ -58,12 +68,19 @@ public class ExecutableContextLayoutNode extends AbstractDMVMNode implements IEl
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
- if (!checkService(IRunControl.class, null, update)) return;
+ TCFDSFRunControl service = getServicesTracker().getService(TCFDSFRunControl.class);
+ if (service == null) {
+ update.setStatus(new Status(IStatus.ERROR,
+ Activator.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "Run Control service not available.", null)); //$NON-NLS-1$
+ handleFailedUpdate(update);
+ return;
+ }
final TCFDSFExecutionDMC dmc = findDmcInPath(update.getViewerInput(),
update.getElementPath(), TCFDSFExecutionDMC.class);
-
- getServicesTracker().getService(TCFDSFRunControl.class).getAllContexts(dmc,
+
+ service.getAllContexts(dmc,
new DataRequestMonitor<IExecutionDMContext[]>(getSession().getExecutor(), null) {
@Override
public void handleCompleted() {
@@ -89,15 +106,27 @@ public class ExecutableContextLayoutNode extends AbstractDMVMNode implements IEl
}
catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
+ update.setStatus(new Status(IStatus.ERROR,
+ Activator.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+ "Cannot execute update request.", e)); //$NON-NLS-1$
handleFailedUpdate(update);
}
}
}
private void updateLabelInSessionThread(final ILabelUpdate[] updates) {
+ TCFDSFRunControl service = getServicesTracker().getService(TCFDSFRunControl.class);
+ if (service == null) {
+ for (final ILabelUpdate update : updates) {
+ update.setStatus(new Status(IStatus.ERROR,
+ Activator.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "Run Control service not available.", null)); //$NON-NLS-1$
+ handleFailedUpdate(update);
+ }
+ return;
+ }
TCFDataCache<?> pending = null;
for (final ILabelUpdate update : updates) {
- if (!checkService(TCFDSFRunControl.class, null, update)) continue;
TCFDSFExecutionDMC dmc = (TCFDSFExecutionDMC)findDmcInPath(update.getViewerInput(),
update.getElementPath(), IContainerDMContext.class);
if (!dmc.run_control_context_cache.validate()) pending = dmc.run_control_context_cache;
@@ -113,7 +142,6 @@ public class ExecutableContextLayoutNode extends AbstractDMVMNode implements IEl
}
for (final ILabelUpdate update : updates) {
- if (!checkService(TCFDSFRunControl.class, null, update)) continue;
TCFDSFExecutionDMC dmc = (TCFDSFExecutionDMC)findDmcInPath(update.getViewerInput(),
update.getElementPath(), IContainerDMContext.class);
@@ -126,7 +154,7 @@ public class ExecutableContextLayoutNode extends AbstractDMVMNode implements IEl
image = IDebugUIConstants.IMG_OBJS_DEBUG_TARGET;
}
else {
- TCFDSFRunControlState state = dmc.run_control_state_cache.getData();
+ TCFContextState state = dmc.run_control_state_cache.getData();
if (state != null && state.is_suspended) {
image = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
}
@@ -150,15 +178,63 @@ public class ExecutableContextLayoutNode extends AbstractDMVMNode implements IEl
}
return IModelDelta.NO_CHANGE;
}
+
+ private List<TCFDSFExecutionDMC> getPath(TCFDSFExecutionDMC dmc) {
+ List<TCFDSFExecutionDMC> list = new ArrayList<TCFDSFExecutionDMC>();
+ while (dmc != null) {
+ list.add(dmc);
+ IDMContext[] up = dmc.getParents();
+ dmc = null;
+ for (IDMContext c: up) {
+ if (c instanceof TCFDSFExecutionDMC) {
+ dmc = (TCFDSFExecutionDMC)c;
+ if (dmc.getTcfContextId() == null) dmc = null;
+ break;
+ }
+ }
+ }
+ return list;
+ }
- public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) {
+ public void buildDelta(final Object e, final VMDelta parentDelta, int nodeOffset, final RequestMonitor rm) {
if (e instanceof IRunControl.IResumedDMEvent || e instanceof IRunControl.ISuspendedDMEvent) {
- parentDelta.addNode(new DMVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.STATE);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ TCFDSFStack.TCFFrameDMC frame = null;
+ TCFDSFExecutionDMC dmc = (TCFDSFExecutionDMC)((IDMEvent<?>)e).getDMContext();
+ /*
+ if (e instanceof IRunControl.ISuspendedDMEvent) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service != null) {
+ TCFDataCache<?> cache = service.getFramesCache(dmc, null);
+ if (!cache.validate()) {
+ cache.wait(this);
+ return;
+ }
+ if (cache.getError() == null) {
+ frame = service.getTopFrame(dmc);
+ }
+ }
+ }
+ */
+ ModelDelta delta = parentDelta;
+ List<TCFDSFExecutionDMC> list = getPath(dmc);
+ for (int i = list.size() - 1; i >= 0; i--) {
+ delta = delta.addNode(createVMContext(list.get(i)),
+ i == 0 ? IModelDelta.CONTENT | IModelDelta.STATE : 0);
+ }
+ if (frame != null) {
+ delta = delta.addNode(createVMContext(frame),
+ IModelDelta.EXPAND | IModelDelta.SELECT);
+ }
+ rm.done();
+ }
+ });
+ return;
}
else if (e instanceof IStartedDMEvent || e instanceof IExitedDMEvent) {
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
- //parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
}
- requestMonitor.done();
+ rm.done();
}
}
diff --git a/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/LaunchVMProvider.java b/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/LaunchVMProvider.java
index 477e3376a..2934513e6 100644
--- a/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/LaunchVMProvider.java
+++ b/plugins/org.eclipse.tm.tcf.dsf.ui/src/org/eclipse/tm/internal/tcf/dsf/ui/viewmodel/LaunchVMProvider.java
@@ -46,7 +46,7 @@ implements IDebugEventSetListener, ILaunchesListener2 {
addChildNodes(launch_node, new IVMNode[] { threads_node });
IVMNode stack_frames_node = new StackFramesVMNode(this, getSession());
- addChildNodes(threads_node, new IVMNode[] { threads_node, stack_frames_node });
+ addChildNodes(threads_node, new IVMNode[] { stack_frames_node, threads_node });
DebugPlugin.getDefault().addDebugEventListener(this);
DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFLaunchSequence.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFLaunchSequence.java
index 6c04def94..21d4ec427 100644
--- a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFLaunchSequence.java
+++ b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFLaunchSequence.java
@@ -33,7 +33,7 @@ class TCFDSFLaunchSequence extends Sequence {
new Step() {
@Override
public void execute(RequestMonitor monitor) {
- new TCFDSFRunControl(launch.getLaunchConfiguration(), session, channel, monitor);
+ new TCFDSFRunControl(launch.getLaunchConfiguration(), launch, session, channel, monitor);
}
},
new Step() {
diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFSourceLookupParticipant.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFSourceLookupParticipant.java
index 9cc4290bc..3ac0bd2ff 100644
--- a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFSourceLookupParticipant.java
+++ b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/launch/TCFDSFSourceLookupParticipant.java
@@ -12,8 +12,8 @@ package org.eclipse.tm.internal.tcf.dsf.launch;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.tm.internal.tcf.debug.launch.TCFSourceLookupParticipant;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
import org.eclipse.tm.internal.tcf.dsf.services.TCFDSFStack.TCFFrameDMC;
-import org.eclipse.tm.internal.tcf.dsf.services.TCFDSFStack.TCFFrameData;
import org.eclipse.tm.tcf.protocol.Protocol;
/**
@@ -26,17 +26,31 @@ public class TCFDSFSourceLookupParticipant extends TCFSourceLookupParticipant {
public String getSourceName(final Object object) throws CoreException {
if (object instanceof TCFFrameDMC) {
final Object[] res = new Object[1];
- Protocol.invokeAndWait(new Runnable() {
- public void run() {
- TCFFrameDMC dmc = (TCFFrameDMC)object;
- if (!dmc.frame_data.validate()) {
- dmc.frame_data.wait(this);
- return;
+ synchronized (res) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ TCFFrameDMC dmc = (TCFFrameDMC)object;
+ if (!dmc.context_cache.validate()) {
+ dmc.context_cache.wait(this);
+ return;
+ }
+ if (!dmc.source_cache.validate()) {
+ dmc.source_cache.wait(this);
+ return;
+ }
+ synchronized (res) {
+ TCFSourceRef ref = dmc.source_cache.getData();
+ if (ref != null) res[0] = ref.area;
+ res.notify();
+ }
}
- TCFFrameData data = dmc.frame_data.getData();
- res[0] = data.code_area;
+ });
+ try {
+ res.wait();
}
- });
+ catch (InterruptedException e) {
+ }
+ }
return super.getSourceName(res[0]);
}
return super.getSourceName(object);
diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFExecutionDMC.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFExecutionDMC.java
index 067a5253f..3f6d30dc7 100644
--- a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFExecutionDMC.java
+++ b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFExecutionDMC.java
@@ -20,6 +20,7 @@ import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryDMContext;
import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.dd.dsf.service.IDsfService;
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.services.IMemory;
@@ -33,7 +34,7 @@ public abstract class TCFDSFExecutionDMC extends AbstractDMContext
public final TCFDataCache<IMemory.MemoryContext> memory_context_cache;
public final TCFDataCache<RunControlContext> run_control_context_cache;
public final TCFDataCache<Map<String,TCFDSFExecutionDMC>> run_control_children_cache;
- public final TCFDataCache<TCFDSFRunControlState> run_control_state_cache;
+ public final TCFDataCache<TCFContextState> run_control_state_cache;
TCFDataCache<?> stack_frames_cache;
TCFDataCache<?> registers_cache;
@@ -104,11 +105,14 @@ public abstract class TCFDSFExecutionDMC extends AbstractDMContext
return false;
}
};
- run_control_state_cache = new TCFDataCache<TCFDSFRunControlState>(channel) {
+ run_control_state_cache = new TCFDataCache<TCFContextState>(channel) {
@Override
public boolean startDataRetrieval() {
assert command == null;
- assert run_control_context_cache.isValid();
+ if (!run_control_context_cache.validate()) {
+ run_control_state_cache.wait(this);
+ return false;
+ }
RunControlContext c = run_control_context_cache.getData();
if (c == null || !c.hasState()) {
reset(null);
@@ -117,8 +121,7 @@ public abstract class TCFDSFExecutionDMC extends AbstractDMContext
command = c.getState(new IRunControl.DoneGetState() {
public void doneGetState(IToken token, Exception err, boolean suspend, String pc, String reason, Map<String,Object> params) {
if (command != token) return;
- TCFDSFRunControlState data = new TCFDSFRunControlState();
- data.is_running = !suspend;
+ TCFContextState data = new TCFContextState();
data.is_suspended = suspend;
if (suspend) {
data.suspend_pc = pc;
diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControl.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControl.java
index b3309a77c..b5ffef8c2 100644
--- a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControl.java
+++ b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControl.java
@@ -31,12 +31,19 @@ import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
+import org.eclipse.tm.internal.tcf.debug.actions.TCFActionStepInto;
+import org.eclipse.tm.internal.tcf.debug.actions.TCFActionStepOut;
+import org.eclipse.tm.internal.tcf.debug.actions.TCFActionStepOver;
import org.eclipse.tm.internal.tcf.debug.model.ITCFConstants;
+import org.eclipse.tm.internal.tcf.debug.model.TCFContextState;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
import org.eclipse.tm.internal.tcf.dsf.Activator;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.services.IRunControl;
import org.eclipse.tm.tcf.services.IRunControl.RunControlContext;
+import org.eclipse.tm.tcf.services.IStackTrace.StackTraceContext;
import org.eclipse.tm.tcf.util.TCFDataCache;
import org.osgi.framework.BundleContext;
@@ -344,7 +351,7 @@ public class TCFDSFRunControl extends AbstractDsfService implements org.eclipse.
void onContextSuspended(String pc, String reason, Map<String,Object> params) {
assert !disposed;
assert !run_control_context_cache.isValid() || run_control_context_cache.getData().hasState();
- TCFDSFRunControlState st = new TCFDSFRunControlState();
+ TCFContextState st = new TCFContextState();
st.is_suspended = true;
st.suspend_pc = pc;
st.suspend_reason = reason;
@@ -356,8 +363,7 @@ public class TCFDSFRunControl extends AbstractDsfService implements org.eclipse.
void onContextResumed() {
assert !disposed;
assert !run_control_context_cache.isValid() || run_control_context_cache.getData().hasState();
- TCFDSFRunControlState st = new TCFDSFRunControlState();
- st.is_running = true;
+ TCFContextState st = new TCFContextState();
run_control_state_cache.reset(st);
getSession().dispatchEvent(new ResumedEvent(this), getProperties());
}
@@ -400,14 +406,17 @@ public class TCFDSFRunControl extends AbstractDsfService implements org.eclipse.
}
private final ILaunchConfiguration config;
+ private final TCFLaunch launch;
private final IChannel channel;
private final org.eclipse.tm.tcf.services.IRunControl tcf_run_service;
private final Map<String,ExecutionDMC> cache = new HashMap<String,ExecutionDMC>();
private final ExecutionDMC root_dmc;
- public TCFDSFRunControl(ILaunchConfiguration config, DsfSession session, IChannel channel, final RequestMonitor monitor) {
+ public TCFDSFRunControl(ILaunchConfiguration config, TCFLaunch launch,
+ DsfSession session, IChannel channel, final RequestMonitor monitor) {
super(session);
this.config = config;
+ this.launch = launch;
this.channel = channel;
tcf_run_service = channel.getRemoteService(org.eclipse.tm.tcf.services.IRunControl.class);
if (tcf_run_service != null) tcf_run_service.addListener(run_listener);
@@ -537,7 +546,28 @@ public class TCFDSFRunControl extends AbstractDsfService implements org.eclipse.
}
else {
RunControlContext c = ctx.run_control_context_cache.getData();
- rm.setData(c != null && c.canResume(toTCFStepType(step_type)));
+ int md = toTCFStepType(step_type);
+ boolean b = c != null && c.canResume(md);
+ if (!b && c != null) {
+ // Check if can emulate desired step type
+ // TODO: check breakpoints service - it is needed to emulate step commands
+ switch (md) {
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER_LINE:
+ b = c.canResume(org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER) ||
+ c.canResume(org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO);
+ break;
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER:
+ b = c.canResume(org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO);
+ break;
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO_LINE:
+ b = c.canResume(org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO);
+ break;
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OUT:
+ b = c.canResume(org.eclipse.tm.tcf.services.IRunControl.RM_RESUME);
+ break;
+ }
+ }
+ rm.setData(b);
rm.done();
}
}
@@ -674,35 +704,260 @@ public class TCFDSFRunControl extends AbstractDsfService implements org.eclipse.
}
return -1;
}
+
+ private class StepIntoAction extends TCFActionStepInto {
+
+ private final ExecutionDMC ctx;
+ private final RequestMonitor monitor;
+
+ private TCFDSFStack.TCFFrameDMC frame;
+
+ StepIntoAction(TCFLaunch launch, ExecutionDMC ctx, RequestMonitor monitor, boolean src_step) {
+ super(launch, ctx.run_control_context_cache.getData(), src_step);
+ this.ctx = ctx;
+ this.monitor = monitor;
+ ctx.is_stepping++;
+ }
+
+ @Override
+ protected TCFDataCache<TCFContextState> getContextState() {
+ return ctx.run_control_state_cache;
+ }
+
+ @Override
+ protected TCFDataCache<TCFSourceRef> getLineInfo() {
+ if (frame == null) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return null;
+ frame = service.getTopFrame(ctx);
+ if (frame == null) return null;
+ }
+ return frame.source_cache;
+ }
- public void step(IExecutionDMContext context, StepType step_type, final RequestMonitor rm) {
+ @Override
+ protected TCFDataCache<StackTraceContext> getStackFrame() {
+ if (frame == null) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return null;
+ frame = service.getTopFrame(ctx);
+ if (frame == null) return null;
+ }
+ return frame.context_cache;
+ }
+
+ @Override
+ protected int getStackFrameIndex() {
+ if (frame == null) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return 0;
+ frame = service.getTopFrame(ctx);
+ if (frame == null) return 0;
+ }
+ return frame.getLevel();
+ }
+
+ @Override
+ protected TCFDataCache<?> getStackTrace() {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return null;
+ return service.getFramesCache(ctx, null);
+ }
+
+ @Override
+ protected void exit(Throwable error) {
+ if (exited) return;
+ super.exit(error);
+ ctx.is_stepping--;
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ }
+ monitor.done();
+ }
+ }
+
+ private class StepOverAction extends TCFActionStepOver {
+
+ private final ExecutionDMC ctx;
+ private final RequestMonitor monitor;
+
+ private TCFDSFStack.TCFFrameDMC frame;
+
+ StepOverAction(TCFLaunch launch, ExecutionDMC ctx, RequestMonitor monitor, boolean src_step) {
+ super(launch, ctx.run_control_context_cache.getData(), src_step);
+ this.ctx = ctx;
+ this.monitor = monitor;
+ ctx.is_stepping++;
+ }
+
+ @Override
+ protected TCFDataCache<TCFContextState> getContextState() {
+ return ctx.run_control_state_cache;
+ }
+
+ @Override
+ protected TCFDataCache<TCFSourceRef> getLineInfo() {
+ if (frame == null) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return null;
+ frame = service.getTopFrame(ctx);
+ if (frame == null) return null;
+ }
+ return frame.source_cache;
+ }
+
+ @Override
+ protected TCFDataCache<StackTraceContext> getStackFrame() {
+ if (frame == null) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return null;
+ frame = service.getTopFrame(ctx);
+ if (frame == null) return null;
+ }
+ return frame.context_cache;
+ }
+
+ @Override
+ protected int getStackFrameIndex() {
+ if (frame == null) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return 0;
+ frame = service.getTopFrame(ctx);
+ if (frame == null) return 0;
+ }
+ return frame.getLevel();
+ }
+
+ @Override
+ protected TCFDataCache<?> getStackTrace() {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return null;
+ return service.getFramesCache(ctx, null);
+ }
+
+ @Override
+ protected void exit(Throwable error) {
+ if (exited) return;
+ super.exit(error);
+ ctx.is_stepping--;
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ }
+ monitor.done();
+ }
+ }
+
+ private class StepOutAction extends TCFActionStepOut {
+
+ private final ExecutionDMC ctx;
+ private final RequestMonitor monitor;
+
+ private TCFDSFStack.TCFFrameDMC frame;
+
+ StepOutAction(TCFLaunch launch, ExecutionDMC ctx, RequestMonitor monitor) {
+ super(launch, ctx.run_control_context_cache.getData());
+ this.ctx = ctx;
+ this.monitor = monitor;
+ ctx.is_stepping++;
+ }
+
+ @Override
+ protected TCFDataCache<TCFContextState> getContextState() {
+ return ctx.run_control_state_cache;
+ }
+
+ @Override
+ protected TCFDataCache<StackTraceContext> getStackFrame() {
+ if (frame == null) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return null;
+ frame = service.getTopFrame(ctx);
+ if (frame == null) return null;
+ }
+ return frame.context_cache;
+ }
+
+ @Override
+ protected int getStackFrameIndex() {
+ if (frame == null) {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return 0;
+ frame = service.getTopFrame(ctx);
+ if (frame == null) return 0;
+ }
+ return frame.getLevel();
+ }
+
+ @Override
+ protected TCFDataCache<?> getStackTrace() {
+ TCFDSFStack service = getServicesTracker().getService(TCFDSFStack.class);
+ if (service == null) return null;
+ return service.getFramesCache(ctx, null);
+ }
+
+ @Override
+ protected void exit(Throwable error) {
+ if (exited) return;
+ super.exit(error);
+ ctx.is_stepping--;
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ }
+ monitor.done();
+ }
+ }
+
+ public void step(final IExecutionDMContext context, final StepType step_type, final RequestMonitor rm) {
if (context instanceof ExecutionDMC) {
final ExecutionDMC ctx = (ExecutionDMC)context;
- if (ctx.run_control_context_cache.isValid()) {
- RunControlContext c = ctx.run_control_context_cache.getData();
- if (c != null) {
- int md = toTCFStepType(step_type);
- if (md < 0) {
- rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
- NOT_SUPPORTED, "Invalid step type", null)); //$NON-NLS-1$
- rm.done();
+ if (!ctx.run_control_context_cache.validate()) {
+ ctx.run_control_context_cache.wait(new Runnable() {
+ public void run() {
+ step(context, step_type, rm);
}
- else {
- c.resume(md, 1, new org.eclipse.tm.tcf.services.IRunControl.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (rm.isCanceled()) return;
- if (error != null) {
- rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
- REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
- }
- ctx.is_stepping--;
- rm.done();
- }
- });
- ctx.is_stepping++;
+ });
+ return;
+ }
+ if (ctx.run_control_context_cache.getError() != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Data error", ctx.run_control_context_cache.getError())); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ RunControlContext c = ctx.run_control_context_cache.getData();
+ if (c != null) {
+ int md = toTCFStepType(step_type);
+ if (md < 0) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ NOT_SUPPORTED, "Invalid step type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ else {
+ switch (md) {
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO:
+ new StepIntoAction(launch, ctx, rm, false);
+ return;
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_INTO_LINE:
+ new StepIntoAction(launch, ctx, rm, true);
+ return;
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER:
+ new StepOverAction(launch, ctx, rm, false);
+ return;
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OVER_LINE:
+ new StepOverAction(launch, ctx, rm, true);
+ return;
+ case org.eclipse.tm.tcf.services.IRunControl.RM_STEP_OUT:
+ new StepOutAction(launch, ctx, rm);
+ return;
}
- return;
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ NOT_SUPPORTED, "Invalid step type", null)); //$NON-NLS-1$
+ rm.done();
}
+ return;
}
rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
@@ -806,7 +1061,7 @@ public class TCFDSFRunControl extends AbstractDsfService implements org.eclipse.
RunControlContext c = ctx.run_control_context_cache.getData();
if (c != null && c.hasState()) {
if (ctx.is_resuming == 0 && ctx.is_stepping == 0 && ctx.run_control_state_cache.isValid()) {
- TCFDSFRunControlState st = ctx.run_control_state_cache.getData();
+ TCFContextState st = ctx.run_control_state_cache.getData();
if (st != null) r = st.is_suspended;
}
}
@@ -820,7 +1075,7 @@ public class TCFDSFRunControl extends AbstractDsfService implements org.eclipse.
ExecutionDMC ctx = (ExecutionDMC)dmc;
StateChangeReason r = StateChangeReason.UNKNOWN;
if (ctx.run_control_state_cache.isValid()) {
- TCFDSFRunControlState st = ctx.run_control_state_cache.getData();
+ TCFContextState st = ctx.run_control_state_cache.getData();
if (st != null && st.suspend_reason != null) {
r = toStateChangeReason(st.suspend_reason);
}
diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControlState.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControlState.java
deleted file mode 100644
index 56ce4fd6e..000000000
--- a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRunControlState.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.eclipse.tm.internal.tcf.dsf.services;
-
-import java.math.BigInteger;
-import java.util.Map;
-
-public class TCFDSFRunControlState {
-
- public boolean is_suspended;
- public boolean is_running;
- public String suspend_pc;
- public String suspend_reason;
- public Map<String,Object> suspend_params;
-
- public TCFAddress getPC() {
- if (suspend_pc == null) return null;
- return new TCFAddress(new BigInteger(suspend_pc));
- }
-}
-
diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java
index 841ebe8ab..d3302f0c0 100644
--- a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java
+++ b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java
@@ -29,6 +29,7 @@ import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.dd.dsf.service.AbstractDsfService;
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef;
import org.eclipse.tm.internal.tcf.dsf.Activator;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
@@ -45,16 +46,17 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
public final String id;
public final TCFDSFExecutionDMC exe_dmc;
- public final TCFDataCache<TCFFrameData> frame_data;
+ public final TCFDataCache<IStackTrace.StackTraceContext> context_cache;
+ public final TCFDataCache<TCFSourceRef> source_cache;
int level;
- TCFFrameData prev_data;
+ TCFSourceRef prev_data;
public TCFFrameDMC(final TCFDSFExecutionDMC exe_dmc, final String id) {
super(TCFDSFStack.this.getSession().getId(), new IDMContext[] { exe_dmc });
this.id = id;
this.exe_dmc = exe_dmc;
- frame_data = new TCFDataCache<TCFFrameData>(channel) {
+ context_cache = new TCFDataCache<IStackTrace.StackTraceContext>(channel) {
@Override
public boolean startDataRetrieval() {
@@ -66,41 +68,53 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
command = tcf_stk_service.getContext(new String[]{ id }, new IStackTrace.DoneGetContext() {
public void doneGetContext(IToken token, Exception err, IStackTrace.StackTraceContext[] context) {
if (command != token) return;
- TCFFrameData data = null;
- TCFAddress a = null;
- Number n = context[0].getInstructionAddress();
- if (n != null) a = new TCFAddress(n);
- // Optimization: skip source position lookup if same address
- if (prev_data != null && prev_data.address != null && prev_data.address.equals(a)) {
- data = prev_data;
- data.context = context[0];
- data.level = level;
- }
- else {
- data = new TCFFrameData();
- data.context = context[0];
- data.address = a;
- data.level = level;
- if (!getSourcePos(data)) return;
- }
- set(token, err, prev_data = data);
+ IStackTrace.StackTraceContext ctx = null;
+ if (context != null && context.length > 0) ctx = context[0];
+ set(token, err, ctx);
}
});
return false;
}
+ };
+
+ source_cache = new TCFDataCache<TCFSourceRef>(channel) {
+
+ @Override
+ protected boolean startDataRetrieval() {
+ if (!context_cache.validate()) {
+ context_cache.wait(this);
+ return false;
+ }
+ IStackTrace.StackTraceContext ctx = context_cache.getData();
+ Number n = ctx.getInstructionAddress();
+ BigInteger a = null;
+ if (n != null) a = new BigInteger(n.toString());
+ // Optimization: skip source position lookup if same address
+ TCFSourceRef data = null;
+ if (prev_data != null && prev_data.address != null && prev_data.address.equals(a)) {
+ data = prev_data;
+ }
+ else {
+ data = new TCFSourceRef();
+ data.address = a;
+ if (!getSourcePos(data)) return false;
+ }
+ set(null, null, prev_data = data);
+ return true;
+ }
- private boolean getSourcePos(final TCFFrameData data) {
+ private boolean getSourcePos(final TCFSourceRef data) {
if (tcf_lns_service == null) return true;
if (data.address == null) return true;
- BigInteger a1 = data.address.getValue();
- BigInteger a2 = data.address.add(1).getValue();
+ BigInteger a1 = data.address;
+ BigInteger a2 = data.address.add(BigInteger.valueOf(1));
command = tcf_lns_service.mapToSource(exe_dmc.getTcfContextId(), a1, a2, new ILineNumbers.DoneMapToSource() {
public void doneMapToSource(IToken token, Exception err, CodeArea[] areas) {
if (command != token) return;
if (areas != null && areas.length > 0) {
for (ILineNumbers.CodeArea area : areas) {
- if (data.code_area == null || area.start_line < data.code_area.start_line) {
- data.code_area = area;
+ if (data.area == null || area.start_line < data.area.start_line) {
+ data.area = area;
}
}
}
@@ -140,12 +154,20 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
public static class TCFFrameData implements IFrameDMData {
- public IStackTrace.StackTraceContext context;
- public IAddress address;
- public int level;
- public String function;
- public Throwable src_pos_error;
- public ILineNumbers.CodeArea code_area;
+ public final IStackTrace.StackTraceContext context;
+ public final IAddress address;
+ public final int level;
+ public final String function;
+ public final ILineNumbers.CodeArea code_area;
+
+ TCFFrameData(TCFFrameDMC dmc) {
+ context = dmc.context_cache.getData();
+ TCFSourceRef ref = dmc.source_cache.getData();
+ address = new TCFAddress(ref.address);
+ level = dmc.getLevel();
+ function = null;
+ code_area = ref.area;
+ }
public IAddress getAddress() {
return address;
@@ -191,6 +213,19 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
@Override
public boolean startDataRetrieval() {
assert command == null;
+ if (!dmc.run_control_context_cache.validate()) {
+ dmc.run_control_context_cache.wait(this);
+ return false;
+ }
+ if (dmc.run_control_context_cache.getError() != null) {
+ set(null, dmc.run_control_context_cache.getError(), null);
+ return true;
+ }
+ org.eclipse.tm.tcf.services.IRunControl.RunControlContext ctx = dmc.run_control_context_cache.getData();
+ if (ctx == null || !ctx.hasState()) {
+ set(null, new Exception("DMC does not have a stack"), null); //$NON-NLS-1$
+ return true;
+ }
if (tcf_stk_service == null) {
HashMap<String,TCFFrameDMC> data = new HashMap<String,TCFFrameDMC>();
top_frame_id = "TopFrame:" + dmc.getTcfContextId();
@@ -225,7 +260,10 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
void invalidateFrames() {
reset();
- for (TCFFrameDMC dmc : frame_pool.values()) dmc.frame_data.reset();
+ for (TCFFrameDMC dmc : frame_pool.values()) {
+ dmc.context_cache.reset();
+ dmc.source_cache.reset();
+ }
}
void dispose() {
@@ -283,22 +321,35 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
public void getFrameData(final IFrameDMContext dmc, final DataRequestMonitor<IFrameDMData> rm) {
if (dmc instanceof TCFFrameDMC) {
final TCFFrameDMC frame_dmc = (TCFFrameDMC)dmc;
- TCFDataCache<TCFFrameData> cache = frame_dmc.frame_data;
- if (!cache.validate()) {
- cache.wait(new Runnable() {
+ if (!frame_dmc.context_cache.validate()) {
+ frame_dmc.context_cache.wait(new Runnable() {
public void run() {
getFrameData(dmc, rm);
}
});
return;
}
- if (cache.getError() != null) {
+ if (frame_dmc.context_cache.getError() != null) {
rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
- REQUEST_FAILED, "Data error", cache.getError())); //$NON-NLS-1$
+ REQUEST_FAILED, "Data error", frame_dmc.context_cache.getError())); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ if (!frame_dmc.source_cache.validate()) {
+ frame_dmc.source_cache.wait(new Runnable() {
+ public void run() {
+ getFrameData(dmc, rm);
+ }
+ });
+ return;
+ }
+ if (frame_dmc.source_cache.getError() != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Data error", frame_dmc.source_cache.getError())); //$NON-NLS-1$
rm.done();
return;
}
- rm.setData(cache.getData());
+ rm.setData(new TCFFrameData(frame_dmc));
rm.done();
}
else {
@@ -308,54 +359,32 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
}
}
- private TCFDataCache<?> createFramesCache(TCFDSFExecutionDMC exe, DataRequestMonitor<?> rm) {
+ public TCFDataCache<?> getFramesCache(TCFDSFExecutionDMC exe, DataRequestMonitor<?> rm) {
if (tcf_stk_service == null) {
- rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
- INVALID_HANDLE, "Stack trace service is not available", null)); //$NON-NLS-1$
- rm.done();
+ if (rm != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Stack trace service is not available", null)); //$NON-NLS-1$
+ rm.done();
+ }
return null;
}
if (exe.isDisposed()) {
- rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
- INVALID_HANDLE, "Disposed DMC", null)); //$NON-NLS-1$
- rm.done();
- return null;
- }
- if (!exe.run_control_context_cache.validate()) {
- return exe.run_control_context_cache;
- }
- if (exe.run_control_context_cache.getError() != null) {
- rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
- REQUEST_FAILED, "Data error", exe.run_control_context_cache.getError())); //$NON-NLS-1$
- rm.done();
- return null;
- }
- org.eclipse.tm.tcf.services.IRunControl.RunControlContext ctx = exe.run_control_context_cache.getData();
- if (ctx == null || !ctx.hasState()) {
- rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
- INVALID_HANDLE, "DMC does not have a stack", null)); //$NON-NLS-1$
- rm.done();
+ if (rm != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Disposed DMC", null)); //$NON-NLS-1$
+ rm.done();
+ }
return null;
}
if (exe.stack_frames_cache == null) exe.stack_frames_cache = new FramesCache(channel, exe);
- return exe.stack_frames_cache;
-
+ return (FramesCache)exe.stack_frames_cache;
}
public void getFrames(final IDMContext dmc, final DataRequestMonitor<IFrameDMContext[]> rm) {
if (dmc instanceof TCFDSFExecutionDMC) {
TCFDSFExecutionDMC exe = (TCFDSFExecutionDMC)dmc;
- TCFDataCache<?> cache0 = createFramesCache(exe, rm);
- if (cache0 == null) return;
- if (cache0 != exe.stack_frames_cache) {
- cache0.wait(new Runnable() {
- public void run() {
- getFrames(dmc, rm);
- }
- });
- return;
- }
- FramesCache cache = (FramesCache)cache0;
+ FramesCache cache = (FramesCache)getFramesCache(exe, rm);
+ if (cache == null) return;
if (!cache.validate()) {
cache.wait(new Runnable() {
public void run() {
@@ -399,17 +428,8 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
public void getStackDepth(final IDMContext dmc, final int maxDepth, final DataRequestMonitor<Integer> rm) {
if (dmc instanceof TCFDSFExecutionDMC) {
TCFDSFExecutionDMC exe = (TCFDSFExecutionDMC)dmc;
- TCFDataCache<?> cache0 = createFramesCache(exe, rm);
- if (cache0 == null) return;
- if (cache0 != exe.stack_frames_cache) {
- cache0.wait(new Runnable() {
- public void run() {
- getStackDepth(dmc, maxDepth, rm);
- }
- });
- return;
- }
- FramesCache cache = (FramesCache)cache0;
+ FramesCache cache = (FramesCache)getFramesCache(exe, rm);
+ if (cache == null) return;
if (!cache.validate()) {
cache.wait(new Runnable() {
public void run() {
@@ -437,17 +457,22 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
public void getTopFrame(final IDMContext dmc, final DataRequestMonitor<IFrameDMContext> rm) {
if (dmc instanceof TCFDSFExecutionDMC) {
TCFDSFExecutionDMC exe = (TCFDSFExecutionDMC)dmc;
- TCFDataCache<?> cache0 = createFramesCache(exe, rm);
- if (cache0 == null) return;
- if (cache0 != exe.stack_frames_cache) {
- cache0.wait(new Runnable() {
+ FramesCache cache = (FramesCache)getFramesCache(exe, rm);
+ if (cache == null) return;
+ if (!cache.validate()) {
+ cache.wait(new Runnable() {
public void run() {
getTopFrame(dmc, rm);
}
});
return;
}
- FramesCache cache = (FramesCache)cache0;
+ if (cache.getError() != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Data error", cache.getError())); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
rm.setData(cache.createFrameDMC(cache.top_frame_id, 0));
rm.done();
}
@@ -457,6 +482,14 @@ public class TCFDSFStack extends AbstractDsfService implements IStack {
rm.done();
}
}
+
+ public TCFFrameDMC getTopFrame(TCFDSFExecutionDMC exe) {
+ FramesCache cache = (FramesCache)getFramesCache(exe, null);
+ assert cache != null;
+ assert cache.isValid();
+ assert cache.getError() == null;
+ return cache.createFrameDMC(cache.top_frame_id, 0);
+ }
public void getVariableData(IVariableDMContext variableDmc, DataRequestMonitor<IVariableDMData> rm) {
// TODO model data for local variables
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/Protocol.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/Protocol.java
index df0ee8144..8d77dea6c 100644
--- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/Protocol.java
+++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/Protocol.java
@@ -11,6 +11,7 @@
package org.eclipse.tm.tcf.protocol;
import java.util.ArrayList;
+import java.util.TreeSet;
import org.eclipse.tm.internal.tcf.core.LocalPeer;
import org.eclipse.tm.internal.tcf.core.Transport;
@@ -24,21 +25,82 @@ import org.eclipse.tm.tcf.services.ILocator;
* 2. local instance of Locator service, which maintains a list of available targets;
* 3. list of open communication channels.
*
+ * It also provides utility methods for posting asynchronous events,
+ * including delayed events (timers).
+ *
+ * Before TCF can be used, it should be given an object implementing IEventQueue interface:
+ * @see #setEventQueue
+ *
* @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
*/
public final class Protocol {
private static IEventQueue event_queue;
+ private static final TreeSet<Timer> timer_queue = new TreeSet<Timer>();
+ private static int timer_cnt;
+ private static class Timer implements Comparable<Timer>{
+ final int id;
+ final long time;
+ final Runnable run;
+
+ Timer(long time, Runnable run) {
+ this.id = timer_cnt++;
+ this.time = time;
+ this.run = run;
+ }
+
+ public int compareTo(Timer x) {
+ if (x == this) return 0;
+ if (time < x.time) return -1;
+ if (time > x.time) return +1;
+ if (id < x.id) return -1;
+ if (id > x.id) return +1;
+ assert false;
+ return 0;
+ }
+ }
+
+ private static final Thread timer_dispatcher = new Thread() {
+ public void run() {
+ try {
+ synchronized (timer_queue) {
+ while (true) {
+ if (timer_queue.isEmpty()) {
+ timer_queue.wait();
+ }
+ else {
+ long time = System.currentTimeMillis();
+ Timer t = timer_queue.first();
+ if (t.time > time) {
+ timer_queue.wait(t.time - time);
+ }
+ else {
+ timer_queue.remove(t);
+ invokeLater(t.run);
+ }
+ }
+ }
+ }
+ }
+ catch (IllegalStateException x) {
+ // Dispatch is shut down, exit this thread
+ }
+ catch (Throwable x) {
+ x.printStackTrace();
+ }
+ }
+ };
+
private static final ArrayList<CongestionMonitor> congestion_monitors = new ArrayList<CongestionMonitor>();
/**
- * Before TCF can be used it should be given an object implementing IEventQueue interface.
+ * Before TCF can be used, it should be given an object implementing IEventQueue interface.
* The implementation maintains a queue of objects implementing Runnable interface and
* executes <code>run</code> methods of that objects in a sequence by a single thread.
* The thread in referred as TCF event dispatch thread. Objects in the queue are called TCF events.
- * Executing <code>run</code> method of an event is also called dispatching of event.
+ * Executing <code>run</code> method of an event is also called dispatching of the event.
*
* Only few methods in TCF APIs are thread safe - can be invoked from any thread.
* If a method description does not say "can be invoked from any thread" explicitly -
@@ -57,6 +119,9 @@ public final class Protocol {
new LocalPeer();
}
});
+ timer_dispatcher.setName("TCF Timer Dispatcher");
+ timer_dispatcher.setDaemon(true);
+ timer_dispatcher.start();
}
/**
@@ -78,7 +143,7 @@ public final class Protocol {
}
/**
- * Causes <code>runnable</code> to have its <code>run</code>
+ * Causes <code>runnable</code> event to have its <code>run</code>
* method called in the dispatch thread of the framework.
* Events are dispatched in same order as queued.
* If invokeLater is called from the dispatching thread
@@ -95,6 +160,31 @@ public final class Protocol {
}
/**
+ * Causes <code>runnable</code> event to have its <code>run</code>
+ * method called in the dispatch thread of the framework.
+ * The event is dispatched after given delay.
+ *
+ * This method can be invoked from any thread.
+ *
+ * @param delay milliseconds to delay event dispatch.
+ * If delay <= 0 the event is posted into the
+ * "ready" queue without delay.
+ * @param runnable the <code>Runnable</code> whose <code>run</code>
+ * method should be executed asynchronously.
+ */
+ public static void invokeLater(long delay, Runnable runnable) {
+ if (delay <= 0) {
+ event_queue.invokeLater(runnable);
+ }
+ else {
+ synchronized (timer_queue) {
+ timer_queue.add(new Timer(System.currentTimeMillis() + delay, runnable));
+ timer_queue.notify();
+ }
+ }
+ }
+
+ /**
* Causes <code>runnable</code> to have its <code>run</code>
* method called in the dispatch thread of the framework.
* Calling thread is suspended until the method is executed.
@@ -186,14 +276,14 @@ public final class Protocol {
}
/**
- * Call back after TCF messages sent by this host up to this moment are delivered
+ * Call back after all TCF messages sent by this host up to this moment are delivered
* to their intended target. This method is intended for synchronization of messages
* across multiple channels.
*
* Note: Cross channel synchronization can reduce performance and throughput.
* Most clients don't need cross channel synchronization and should not call this method.
*
- * @param done will be executed by dispatch thread after communication
+ * @param done will be executed by dispatch thread after pending communication
* messages are delivered to corresponding targets.
*/
public static void sync(Runnable done) {

Back to the top