Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2008-04-07 17:19:16 +0000
committereutarass2008-04-07 17:19:16 +0000
commit3c90f4ac3612c74dd8309c85c6a96c77d860156c (patch)
treefcbd32366f0d90ea8abce04707feae360e62669f /plugins/org.eclipse.tm.tcf.debug.ui
parent74ecb17420fdbd286c06b324a8208c72175b0cf2 (diff)
downloadorg.eclipse.tcf-3c90f4ac3612c74dd8309c85c6a96c77d860156c.tar.gz
org.eclipse.tcf-3c90f4ac3612c74dd8309c85c6a96c77d860156c.tar.xz
org.eclipse.tcf-3c90f4ac3612c74dd8309c85c6a96c77d860156c.zip
TCF debugger prototype: remote data caching logic is redesigned in order to improve performance and simplify the code.
Diffstat (limited to 'plugins/org.eclipse.tm.tcf.debug.ui')
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/ImageCache.java50
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchAdapterFactory.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java41
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java92
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java235
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java42
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java80
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDataCache.java178
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java83
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java31
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java257
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java489
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java49
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java285
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java249
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java24
17 files changed, 1219 insertions, 978 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/ImageCache.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/ImageCache.java
new file mode 100644
index 000000000..b97b06076
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/ImageCache.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.ui;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.osgi.framework.Bundle;
+
+public class ImageCache {
+
+ private static final Map<String,ImageDescriptor> image_cache = new HashMap<String,ImageDescriptor>();
+
+ public static ImageDescriptor getImageDescriptor(String name) {
+ if (name == null) return null;
+ ImageDescriptor descriptor = image_cache.get(name);
+ if (descriptor == null) {
+ Bundle bundle = Platform.getBundle(Activator.PLUGIN_ID);
+ if (bundle != null){
+ URL url = FileLocator.find(bundle, new Path(name), null);
+ if (url != null) descriptor = ImageDescriptor.createFromURL(url);
+ }
+ if (descriptor == null) {
+ bundle = Platform.getBundle("org.eclipse.debug.ui");
+ if (bundle != null){
+ URL url = FileLocator.find(bundle, new Path(name), null);
+ if (url != null) descriptor = ImageDescriptor.createFromURL(url);
+ }
+ }
+ if (descriptor == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ image_cache.put(name, descriptor);
+ }
+ return descriptor;
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchAdapterFactory.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchAdapterFactory.java
index 616297dee..c68394991 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchAdapterFactory.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchAdapterFactory.java
@@ -31,9 +31,14 @@ public class TCFLaunchAdapterFactory implements IAdapterFactory {
ITerminateHandler.class
};
+ private final IElementLabelProvider launch_label_provider = new TCFLaunchLabelProvider();
+
@SuppressWarnings("unchecked")
public Object getAdapter(final Object from, final Class to) {
if (from instanceof TCFLaunch) {
+ if (to.equals(IElementLabelProvider.class)) {
+ return launch_label_provider;
+ }
final Object[] res = new Object[1];
Protocol.invokeAndWait(new Runnable() {
public void run() {
@@ -54,7 +59,6 @@ public class TCFLaunchAdapterFactory implements IAdapterFactory {
});
if (res[0] != null) return res[0];
}
- System.err.println(from.getClass().getName() + " -> " + to);
return null;
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java
new file mode 100644
index 000000000..2bf9f6a8d
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/adapters/TCFLaunchLabelProvider.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.ui.adapters;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
+
+class TCFLaunchLabelProvider implements IElementLabelProvider {
+
+ public void update(ILabelUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ ILabelUpdate result = updates[i];
+ TCFLaunch launch = (TCFLaunch)result.getElement();
+ result.setImageDescriptor(ImageCache.getImageDescriptor("icons/tcf.gif"), 0);
+ String status = "";
+ if (launch.isConnecting()) status = "Connecting";
+ else if (launch.isDisconnected()) status = "Disconnected";
+ else if (launch.isTerminated()) status = "Terminated";
+ Throwable error = launch.getError();
+ if (error != null) {
+ status += " - " + error;
+ result.setForeground(new RGB(255, 0, 0), 0);
+ }
+ if (status.length() > 0) status = " (" + status + ")";
+ String label = launch.getLaunchConfiguration().getName() + status;
+ result.setLabel(label, 0);
+ result.done();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java
index 1fb8e602d..12bae4898 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java
@@ -10,62 +10,94 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.model;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
-public class TCFChildren {
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IToken;
- final TCFNode node;
- final Map<String,TCFNode> children = new HashMap<String,TCFNode>();
+/**
+ * TCFChildren is a concrete type of TCF data cache that is used to cache a list of children.
+ */
+public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> {
- protected boolean valid;
+ private final int pool_margin;
+ private final Map<String,TCFNode> node_pool = new LinkedHashMap<String,TCFNode>(32, 0.75f, true);
+
+ TCFChildren(IChannel channel) {
+ super(channel);
+ pool_margin = 0;
+ }
- TCFChildren(TCFNode node) {
- this.node = node;
+ TCFChildren(IChannel channel, int pool_margin) {
+ super(channel);
+ this.pool_margin = pool_margin;
}
void dispose() {
- TCFNode a[] = children.values().toArray(new TCFNode[children.size()]);
+ if (node_pool.isEmpty()) return;
+ TCFNode a[] = node_pool.values().toArray(new TCFNode[node_pool.size()]);
for (int i = 0; i < a.length; i++) a[i].dispose();
- assert children.isEmpty();
+ assert node_pool.isEmpty();
}
void dispose(String id) {
- children.remove(id);
+ node_pool.remove(id);
+ if (isValid()) getData().remove(id);
+ }
+
+ private void flush(Map<String,TCFNode> data) {
+ node_pool.putAll(data);
+ if (node_pool.size() > data.size() + pool_margin) {
+ String[] arr = node_pool.keySet().toArray(new String[node_pool.size()]);
+ for (String id : arr) {
+ if (data.get(id) == null) {
+ node_pool.get(id).dispose();
+ if (node_pool.size() <= data.size() + pool_margin) break;
+ }
+ }
+ }
+ }
+
+ public void set(IToken token, Throwable error, Map<String,TCFNode> data) {
+ if (data != null) {
+ super.set(token, error, data);
+ flush(data);
+ }
+ else {
+ super.set(token, error, new HashMap<String,TCFNode>());
+ }
}
- void doneValidate(Map<String,TCFNode> new_children) {
- assert !node.disposed;
- assert !valid;
- valid = true;
- if (children.size() > 0) {
- TCFNode[] a = children.values().toArray(new TCFNode[children.size()]);
- for (TCFNode n : a) if (new_children.get(n.id) != n) n.dispose();
+ public void reset(Map<String,TCFNode> data) {
+ if (data != null) {
+ super.reset(data);
+ flush(data);
}
- for (TCFNode n : new_children.values()) {
- assert n.parent == node;
- children.put(n.id, n);
+ else {
+ super.reset(new HashMap<String,TCFNode>());
}
- assert children.size() == new_children.size();
}
- boolean validate() {
- doneValidate(new HashMap<String,TCFNode>());
- return true;
+ void add(TCFNode n) {
+ node_pool.put(n.id, n);
+ if (isValid()) getData().put(n.id, n);
}
- void invalidate() {
- assert !node.disposed;
- TCFNode[] a = children.values().toArray(new TCFNode[children.size()]);
- for (int i = 0; i < a.length; i++) a[i].invalidateNode();
- valid = false;
+ Collection<TCFNode> getNodes() {
+ return node_pool.values();
}
int size() {
- return children.size();
+ assert isValid();
+ return getData().size();
}
TCFNode[] toArray() {
- return children.values().toArray(new TCFNode[children.size()]);
+ assert isValid();
+ Map<String,TCFNode> data = getData();
+ return data.values().toArray(new TCFNode[data.size()]);
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
index d31df810c..343edfb29 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
@@ -11,7 +11,6 @@
package org.eclipse.tm.internal.tcf.debug.ui.model;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -29,8 +28,9 @@ import org.eclipse.tm.tcf.services.IRunControl;
@SuppressWarnings("serial")
public class TCFChildrenExecContext extends TCFChildren {
- private Map<String,TCFNode> mem_children;
- private Map<String,TCFNode> run_children;
+ private final TCFNode node;
+ private final TCFChildren mem_children;
+ private final TCFChildren run_children;
// Track disposed IDs to detect violations of the communication protocol
private LinkedHashMap<String,String> disposed_ids = new LinkedHashMap<String,String>() {
@@ -39,162 +39,127 @@ public class TCFChildrenExecContext extends TCFChildren {
}
};
- TCFChildrenExecContext(TCFNode node) {
- super(node);
+ TCFChildrenExecContext(final TCFNode node) {
+ super(node.model.getLaunch().getChannel());
+ this.node = node;
+ mem_children = new TCFChildren(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ IMemory mem = node.model.getLaunch().getService(IMemory.class);
+ if (mem == null) {
+ set(null, null, new HashMap<String,TCFNode>());
+ return true;
+ }
+ assert command == null;
+ command = mem.getChildren(node.id, new IMemory.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ Map<String,TCFNode> data = null;
+ if (command == token && error == null) {
+ data = new HashMap<String,TCFNode>();
+ for (String id : contexts) {
+ assert disposed_ids.get(id) == null;
+ TCFNode n = node.model.getNode(id);
+ if (n == null) n = new TCFNodeExecContext(node, id);
+ data.put(id, n);
+ }
+ }
+ set(token, error, data);
+ }
+ });
+ return false;
+ }
+ };
+ run_children = new TCFChildren(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ IRunControl run = node.model.getLaunch().getService(IRunControl.class);
+ if (run == null) {
+ set(null, null, new HashMap<String,TCFNode>());
+ return true;
+ }
+ assert command == null;
+ command = run.getChildren(node.id, new IRunControl.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ Map<String,TCFNode> data = null;
+ if (command == token && error == null) {
+ data = new HashMap<String,TCFNode>();
+ for (String id : contexts) {
+ assert disposed_ids.get(id) == null;
+ TCFNode n = node.model.getNode(id);
+ if (n == null) n = new TCFNodeExecContext(node, id);
+ data.put(id, n);
+ }
+ }
+ set(token, error, data);
+ }
+ });
+ return false;
+ }
+ };
}
@Override
- void dispose() {
- HashSet<TCFNode> s = new HashSet<TCFNode>();
- s.addAll(children.values());
- if (mem_children != null) s.addAll(mem_children.values());
- if (run_children != null) s.addAll(run_children.values());
- for (TCFNode n : s) n.dispose();
- mem_children = null;
- run_children = null;
+ protected void dispose() {
+ super.dispose();
+ mem_children.dispose();
+ run_children.dispose();
}
@Override
void dispose(String id) {
super.dispose(id);
- if (mem_children != null) mem_children.remove(id);
- if (run_children != null) run_children.remove(id);
+ mem_children.dispose(id);
+ run_children.dispose(id);
disposed_ids.put(id, id);
}
@Override
- boolean validate() {
- assert !node.disposed;
- Map<String,TCFNode> new_children = new HashMap<String,TCFNode>();
- if (!validateMemoryChildren(new_children)) return false;
- if (!validateRunControlChildren(new_children)) return false;
- doneValidate(new_children);
+ protected boolean startDataRetrieval() {
+ TCFDataCache<?> pending = null;
+ if (!mem_children.validate()) pending = mem_children;
+ if (!run_children.validate()) pending = run_children;
+ if (pending != null) {
+ pending.wait(this);
+ return false;
+ }
+ Throwable error = null;
+ Map<String,TCFNode> data = new HashMap<String,TCFNode>();
+ if (mem_children.getError() == null) data.putAll(mem_children.getData());
+ else error = mem_children.getError();
+ if (run_children.getError() == null) data.putAll(run_children.getData());
+ else error = run_children.getError();
+ set(null, error, data);
return true;
}
- @Override
- void invalidate() {
- HashSet<TCFNode> s = new HashSet<TCFNode>();
- s.addAll(children.values());
- if (mem_children != null) s.addAll(mem_children.values());
- if (run_children != null) s.addAll(run_children.values());
- for (TCFNode n : s) n.invalidateNode();
- mem_children = null;
- run_children = null;
- valid = false;
- }
-
void onContextAdded(IRunControl.RunControlContext context) {
- assert !node.disposed;
- if (run_children != null) {
- String id = context.getID();
- TCFNodeExecContext n = (TCFNodeExecContext)node.model.getNode(id);
- if (n == null) {
- n = new TCFNodeExecContext(node, id);
- n.setRunContext(context);
- n.makeModelDelta(IModelDelta.INSERTED);
- }
- else {
- n.setRunContext(context);
- n.makeModelDelta(IModelDelta.STATE);
- }
- children.put(id, n);
- run_children.put(id, n);
- }
- else {
- node.invalidateNode();
+ String id = context.getID();
+ TCFNodeExecContext n = (TCFNodeExecContext)node.model.getNode(id);
+ if (n == null) {
+ n = new TCFNodeExecContext(node, id);
node.makeModelDelta(IModelDelta.CONTENT);
}
+ else {
+ n.makeModelDelta(IModelDelta.STATE);
+ }
+ add(n);
+ run_children.add(n);
+ n.setRunContext(context);
}
void onContextAdded(IMemory.MemoryContext context) {
assert !node.disposed;
- if (mem_children != null) {
- String id = context.getID();
- TCFNodeExecContext n = (TCFNodeExecContext)node.model.getNode(id);
- if (n == null) {
- n = new TCFNodeExecContext(node, id);
- n.setMemoryContext(context);
- n.makeModelDelta(IModelDelta.INSERTED);
- }
- else {
- n.setMemoryContext(context);
- n.makeModelDelta(IModelDelta.STATE);
- }
- children.put(id, n);
- mem_children.put(id, n);
- }
- else {
- node.invalidateNode();
+ String id = context.getID();
+ TCFNodeExecContext n = (TCFNodeExecContext)node.model.getNode(id);
+ if (n == null) {
+ n = new TCFNodeExecContext(node, id);
node.makeModelDelta(IModelDelta.CONTENT);
}
- }
-
- private boolean validateMemoryChildren(final Map<String,TCFNode> new_children) {
- if (mem_children != null) {
- new_children.putAll(mem_children);
- return true;
- }
- IMemory mem = node.model.getLaunch().getService(IMemory.class);
- if (mem == null) {
- mem_children = new HashMap<String,TCFNode>();
- return true;
+ else {
+ n.makeModelDelta(IModelDelta.STATE);
}
- assert node.pending_command == null;
- node.pending_command = mem.getChildren(node.id, new IMemory.DoneGetChildren() {
- public void doneGetChildren(IToken token, Exception error, String[] contexts) {
- if (node.pending_command != token) return;
- node.pending_command = null;
- mem_children = new_children;
- mem_children.clear();
- if (error != null) {
- node.node_error = error;
- }
- else {
- for (String id : contexts) {
- assert disposed_ids.get(id) == null;
- TCFNode n = node.model.getNode(id);
- if (n == null) n = new TCFNodeExecContext(node, id);
- mem_children.put(id, n);
- }
- }
- node.validateNode();
- }
- });
- return false;
- }
-
- private boolean validateRunControlChildren(final Map<String,TCFNode> new_children) {
- if (run_children != null) {
- new_children.putAll(run_children);
- return true;
- }
- IRunControl run = node.model.getLaunch().getService(IRunControl.class);
- if (run == null) {
- run_children = new HashMap<String,TCFNode>();
- return true;
- }
- assert node.pending_command == null;
- node.pending_command = run.getChildren(node.id, new IRunControl.DoneGetChildren() {
- public void doneGetChildren(IToken token, Exception error, String[] contexts) {
- if (node.pending_command != token) return;
- node.pending_command = null;
- run_children = new_children;
- run_children.clear();
- if (error != null) {
- node.node_error = error;
- }
- else {
- for (String id : contexts) {
- assert disposed_ids.get(id) == null;
- TCFNode n = node.model.getNode(id);
- if (n == null) n = new TCFNodeExecContext(node, id);
- run_children.put(id, n);
- }
- }
- node.validateNode();
- }
- });
- return false;
+ add(n);
+ mem_children.add(n);
+ n.setMemoryContext(context);
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java
index 050bbfa7b..92998f559 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenRegisters.java
@@ -19,52 +19,44 @@ import org.eclipse.tm.tcf.services.IRegisters;
public class TCFChildrenRegisters extends TCFChildren {
- private boolean running;
+ private final TCFNode node;
TCFChildrenRegisters(TCFNode node) {
- super(node);
+ super(node.model.getLaunch().getChannel());
+ this.node = node;
}
/**
* Invalidate register values only, keep cached register attributes.
*/
void onSuspended() {
- if (running || node.node_error != null) invalidate();
- for (TCFNode n : children.values()) ((TCFNodeRegister)n).onSuspended();
+ for (TCFNode n : getNodes()) ((TCFNodeRegister)n).onSuspended();
+ }
+
+ void onRegistersChanged() {
+ for (TCFNode n : getNodes()) ((TCFNodeRegister)n).onRegistersChanged();
}
@Override
- boolean validate() {
- assert !node.disposed;
- assert !valid;
- final Map<String,TCFNode> new_children = new HashMap<String,TCFNode>();
- running = !node.isSuspended();
- if (running) {
- valid = true;
- return true;
- }
+ protected boolean startDataRetrieval() {
IRegisters regs = node.model.getLaunch().getService(IRegisters.class);
if (regs == null) {
- doneValidate(new_children);
+ set(null, null, new HashMap<String,TCFNode>());
return true;
}
- assert node.pending_command == null;
- node.pending_command = regs.getChildren(node.id, new IRegisters.DoneGetChildren() {
+ assert command == null;
+ command = regs.getChildren(node.id, new IRegisters.DoneGetChildren() {
public void doneGetChildren(IToken token, Exception error, String[] contexts) {
- if (node.pending_command != token) return;
- node.pending_command = null;
- if (error != null) {
- node.node_error = error;
- }
- else {
+ Map<String,TCFNode> data = null;
+ if (command == token && error == null) {
+ data = new HashMap<String,TCFNode>();
for (String id : contexts) {
TCFNode n = node.model.getNode(id);
if (n == null) n = new TCFNodeRegister(node, id);
- new_children.put(id, n);
+ data.put(id, n);
}
}
- doneValidate(new_children);
- node.validateNode();
+ set(token, error, data);
}
});
return false;
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
index ee77630e9..071641cfa 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
@@ -11,7 +11,6 @@
package org.eclipse.tm.internal.tcf.debug.ui.model;
import java.util.HashMap;
-import java.util.Map;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.services.IStackTrace;
@@ -19,95 +18,68 @@ import org.eclipse.tm.tcf.services.IStackTrace;
public class TCFChildrenStackTrace extends TCFChildren {
+ private final TCFNodeExecContext node;
private final TCFChildrenRegisters children_regs;
- private final Map<String,TCFNodeStackFrame> frames_cache =
- new HashMap<String,TCFNodeStackFrame>();
-
- TCFChildrenStackTrace(TCFNode node, TCFChildrenRegisters children_regs) {
- super(node);
+ TCFChildrenStackTrace(TCFNodeExecContext node, TCFChildrenRegisters children_regs) {
+ super(node.model.getLaunch().getChannel(), 16);
+ this.node = node;
this.children_regs = children_regs;
}
- @Override
- void dispose() {
- TCFNode arr[] = frames_cache.values().toArray(new TCFNode[frames_cache.size()]);
- for (int i = 0; i < arr.length; i++) arr[i].dispose();
- assert frames_cache.isEmpty();
- assert children.isEmpty();
- }
-
- @Override
- void dispose(String id) {
- super.dispose(id);
- frames_cache.remove(id);
- }
-
void onSourceMappingChange() {
- for (TCFNodeStackFrame n : frames_cache.values()) n.onSourceMappingChange();
+ for (TCFNode n : getNodes()) ((TCFNodeStackFrame)n).onSourceMappingChange();
}
void onSuspended() {
- for (TCFNodeStackFrame n : frames_cache.values()) n.onSuspended();
- valid = false;
+ for (TCFNode n : getNodes()) ((TCFNodeStackFrame)n).onSuspended();
+ reset();
+ }
+
+ void onRegistersChanged() {
+ for (TCFNode n : getNodes()) ((TCFNodeStackFrame)n).onRegistersChanged();
}
void onResumed() {
- valid = false;
+ reset(null);
}
@Override
- boolean validate() {
- final Map<String,TCFNode> new_children = new HashMap<String,TCFNode>();
+ protected boolean startDataRetrieval() {
+ final HashMap<String,TCFNode> data = new HashMap<String,TCFNode>();
if (!node.isSuspended()) {
- doneValidate(new_children);
+ set(null, null, data);
return true;
}
String nm = node.id + "-TF";
- TCFNodeStackFrame n = frames_cache.get(nm);
- if (n == null) n = (TCFNodeStackFrame)node.model.getNode(nm);
+ TCFNodeStackFrame n = (TCFNodeStackFrame)node.model.getNode(nm);
if (n == null) n = new TCFNodeStackFrame(node, nm, children_regs);
- new_children.put(n.id, n);
- frames_cache.put(n.id, n);
+ data.put(n.id, n);
IStackTrace st = node.model.getLaunch().getService(IStackTrace.class);
if (st == null) {
- doneValidate(new_children);
+ set(null, null, data);
return true;
}
- assert node.pending_command == null;
- node.pending_command = st.getChildren(node.id, new IStackTrace.DoneGetChildren() {
+ assert command == null;
+ command = st.getChildren(node.id, new IStackTrace.DoneGetChildren() {
public void doneGetChildren(IToken token, Exception error, String[] contexts) {
- if (node.pending_command != token) return;
- node.pending_command = null;
- if (error != null) {
- node.node_error = error;
- }
- else {
+ if (command == token && error == null) {
int cnt = contexts.length;
for (String id : contexts) {
- TCFNodeStackFrame n = frames_cache.get(id);
- if (n == null) n = (TCFNodeStackFrame)node.model.getNode(id);
+ TCFNodeStackFrame n = (TCFNodeStackFrame)node.model.getNode(id);
if (n == null || n.getFrameNo() != cnt) {
if (n != null) n.dispose();
n = new TCFNodeStackFrame(node, id, cnt);
}
- assert n.getFrameNo() == cnt;
+ assert n.getFrameNo() != 0;
assert n.id.equals(id);
assert n.parent == node;
- new_children.put(id, n);
- frames_cache.put(id, n);
+ n.setFrameNo(cnt);
+ data.put(id, n);
cnt--;
}
- if (frames_cache.size() > new_children.size() + 32) {
- // Trim frame cache
- TCFNode arr[] = frames_cache.values().toArray(new TCFNode[frames_cache.size()]);
- for (int i = 0; i < arr.length; i++) {
- if (new_children.get(arr[i].id) == null) arr[i].dispose();
- }
- }
}
- doneValidate(new_children);
- node.validateNode();
+ set(token, error, data);
}
});
return false;
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDataCache.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDataCache.java
new file mode 100644
index 000000000..5584a02ed
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDataCache.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * 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.ui.model;
+
+import java.util.HashSet;
+
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+
+/**
+ * Objects of this class are used cache TCF remote data.
+ * The cache is asynchronous state machine. The states are:
+ * 1. Valid - cache is in sync with remote data, use getError() and getData() to get cached data;
+ * 2. Invalid - cache is out out of sync, start data retrieval by calling validate();
+ * 3. Pending - cache is waiting result of a command that was sent to remote peer.
+ * @param <V> - type of data to be stored in the cache.
+ */
+public abstract class TCFDataCache<V> implements Runnable {
+
+ private Throwable error;
+ private boolean valid;
+ private V data;
+
+ protected final IChannel channel;
+ protected IToken command;
+
+ private final HashSet<Runnable> waiting_list = new HashSet<Runnable>();
+
+ public TCFDataCache(IChannel channel) {
+ assert channel != null;
+ this.channel = channel;
+ }
+
+ /**
+ * @return true if cache contains up-to-date data (or data error).
+ */
+ public boolean isValid() {
+ return valid;
+ }
+
+ /**
+ * @return true if data retrieval is in progress.
+ */
+ public boolean isPending() {
+ return command != null;
+ }
+
+ /**
+ * @return error object if data retrieval ended with an error, or null if retrieval was successful.
+ * Note: It is prohibited to call this method when cache is not valid.
+ */
+ public Throwable getError() {
+ assert valid;
+ return error;
+ }
+
+ /**
+ * @return cached data object.
+ * Note: It is prohibited to call this method when cache is not valid.
+ */
+ public V getData() {
+ assert valid;
+ return data;
+ }
+
+ /**
+ * Notify waiting clients about cache state change and remove then from wait list.
+ * It is responsibility of clients to check if state change was one they are waiting for.
+ */
+ public void run() {
+ if (waiting_list.isEmpty()) return;
+ Runnable[] arr = waiting_list.toArray(new Runnable[waiting_list.size()]);
+ waiting_list.clear();
+ for (Runnable r : arr) r.run();
+ }
+
+ /**
+ * Add a client call-back to cache wait list.
+ * @param req
+ */
+ public void wait(Runnable cb) {
+ assert !valid;
+ if (cb != null) waiting_list.add(cb);
+ }
+
+ /**
+ * Initiate data retrieval if the cache is not valid.
+ * @return
+ */
+ public boolean validate() {
+ assert Protocol.isDispatchThread();
+ if (channel.getState() != IChannel.STATE_OPEN) {
+ error = null;
+ command = null;
+ valid = true;
+ data = null;
+ }
+ else {
+ if (command != null) return false;
+ if (!valid && !startDataRetrieval()) return false;
+ }
+ assert valid;
+ assert command == null;
+ run();
+ return true;
+ }
+
+ /**
+ * End cache pending state.
+ * @param token - pending command handle.
+ * @param error - data retrieval error or null
+ * @param data - up-to-date data object
+ */
+ public void set(IToken token, Throwable error, V data) {
+ assert Protocol.isDispatchThread();
+ if (command != token) return;
+ command = null;
+ if (channel.getState() != IChannel.STATE_OPEN) data = null;
+ this.error = error;
+ this.data = data;
+ valid = true;
+ run();
+ }
+
+ /**
+ * Force cache to become valid, cancel pending data retrieval if any.
+ * @param data - up-to-date data object
+ */
+ public void reset(V data) {
+ if (command != null) {
+ command.cancel();
+ command = null;
+ }
+ this.data = data;
+ error = null;
+ valid = true;
+ run();
+ }
+
+ /**
+ * Invalidate the cache. If retrieval is in progress - let it continue.
+ */
+ public void reset() {
+ error = null;
+ valid = false;
+ data = null;
+ run();
+ }
+
+ /**
+ * Force cache to invalid state, cancel pending data retrieval if any.
+ */
+ public void cancel() {
+ if (command != null) {
+ command.cancel();
+ command = null;
+ }
+ error = null;
+ valid = false;
+ data = null;
+ run();
+ }
+
+ /**
+ * Sub-classes should override this method to implement actual data retrieval logic.
+ * @return true is all done, false if retrieval is in progress.
+ */
+ protected abstract boolean startDataRetrieval();
+}
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 cddebcf9a..8ebb9c1d9 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
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.model;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
@@ -33,7 +34,6 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
@@ -55,15 +55,14 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
private final Display display;
private final TCFLaunch launch;
- private final TCFNodeLaunch launch_node;
private final Map<IPresentationContext,TCFModelProxy> model_proxies =
new HashMap<IPresentationContext,TCFModelProxy>();
private final Map<String,TCFNode> id2node = new HashMap<String,TCFNode>();
- private final Map<TCFNode,ModelDelta> deltas = new HashMap<TCFNode,ModelDelta>();
@SuppressWarnings("unchecked")
private final Map<Class,Object> commands = new HashMap<Class,Object>();
private final TreeSet<FutureTask> queue = new TreeSet<FutureTask>();
+ private TCFNodeLaunch launch_node;
private boolean disposed;
private int future_task_cnt;
@@ -276,7 +275,6 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
TCFModel(Display display, TCFLaunch launch) {
this.display = display;
this.launch = launch;
- launch_node = new TCFNodeLaunch(TCFModel.this);
commands.put(ISuspendHandler.class, new SuspendCommand(this));
commands.put(IResumeHandler.class, new ResumeCommand(this));
commands.put(ITerminateHandler.class, new TerminateCommand(this));
@@ -297,13 +295,13 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
void onConnected() {
assert Protocol.isDispatchThread();
+ launch_node = new TCFNodeLaunch(this);
IMemory mem = launch.getService(IMemory.class);
if (mem != null) mem.addListener(mem_listener);
IRunControl run = launch.getService(IRunControl.class);
if (run != null) run.addListener(run_listener);
IRegisters reg = launch.getService(IRegisters.class);
if (reg != null) reg.addListener(reg_listener);
- launch_node.invalidateNode();
launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
fireModelChanged();
}
@@ -334,9 +332,15 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
});
}
+ Collection<TCFModelProxy> getModelProxyList() {
+ return model_proxies.values();
+ }
+
void launchChanged() {
- launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
- fireModelChanged();
+ if (launch_node != null) {
+ launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ fireModelChanged();
+ }
}
void dispose() {
@@ -365,25 +369,10 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
assert Protocol.isDispatchThread();
id2node.remove(id);
}
-
- ModelDelta getDelta(TCFNode node) {
- return deltas.get(node);
- }
-
- void addDelta(TCFNode node, ModelDelta delta) {
- assert deltas.get(node) == null;
- deltas.put(node, delta);
- }
-
+
void fireModelChanged() {
assert Protocol.isDispatchThread();
- ModelDelta delta = deltas.get(launch_node);
- assert (delta == null) == deltas.isEmpty();
- if (delta != null) {
- deltas.clear();
- IModelDelta top = delta.getParentDelta();
- for (TCFModelProxy p : model_proxies.values()) p.fireModelChanged(top);
- }
+ for (TCFModelProxy p : model_proxies.values()) p.fireModelChanged();
}
public Display getDisplay() {
@@ -415,33 +404,61 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
public void update(IChildrenCountUpdate[] updates) {
for (int i = 0; i < updates.length; i++) {
Object o = updates[i].getElement();
- if (o instanceof TCFLaunch) launch_node.update(updates[i]);
- else ((TCFNode)o).update(updates[i]);
+ if (o instanceof TCFLaunch) {
+ if (launch_node != null) {
+ launch_node.update(updates[i]);
+ }
+ else {
+ updates[i].setChildCount(0);
+ updates[i].done();
+ }
+ }
+ else {
+ ((TCFNode)o).update(updates[i]);
+ }
}
}
public void update(IChildrenUpdate[] updates) {
for (int i = 0; i < updates.length; i++) {
Object o = updates[i].getElement();
- if (o instanceof TCFLaunch) launch_node.update(updates[i]);
- else ((TCFNode)o).update(updates[i]);
+ if (o instanceof TCFLaunch) {
+ if (launch_node != null) {
+ launch_node.update(updates[i]);
+ }
+ else {
+ updates[i].done();
+ }
+ }
+ else {
+ ((TCFNode)o).update(updates[i]);
+ }
}
}
public void update(IHasChildrenUpdate[] updates) {
for (int i = 0; i < updates.length; i++) {
Object o = updates[i].getElement();
- if (o instanceof TCFLaunch) launch_node.update(updates[i]);
- else ((TCFNode)o).update(updates[i]);
+ if (o instanceof TCFLaunch) {
+ if (launch_node != null) {
+ launch_node.update(updates[i]);
+ }
+ else {
+ updates[i].setHasChilren(false);
+ updates[i].done();
+ }
+ }
+ else {
+ ((TCFNode)o).update(updates[i]);
+ }
}
}
public void update(ILabelUpdate[] updates) {
for (int i = 0; i < updates.length; i++) {
Object o = updates[i].getElement();
- assert o != launch_node;
- if (o instanceof TCFLaunch) launch_node.update(updates[i]);
- else ((TCFNode)o).update(updates[i]);
+ assert !(o instanceof TCFLaunch);
+ ((TCFNode)o).update(updates[i]);
}
}
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 b979d7989..4b5f0efee 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
@@ -19,6 +19,7 @@ import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchesListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
+import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.Protocol;
@@ -102,7 +103,10 @@ public class TCFModelManager {
if (model == null) {
model = new TCFModel(display, launch);
models.put(launch, model);
- if (launch.getChannel() != null) tcf_launch_listener.onConnected(launch);
+ IChannel channel = launch.getChannel();
+ if (channel != null && channel.getState() == IChannel.STATE_OPEN) {
+ tcf_launch_listener.onConnected(launch);
+ }
}
return model;
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
index 6eb014de3..ac5694bc1 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
@@ -10,13 +10,21 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.model;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.tm.tcf.protocol.Protocol;
public class TCFModelProxy extends AbstractModelProxy implements IModelProxy {
private final TCFModel model;
+ private final Map<TCFNode,ModelDelta> deltas = new HashMap<TCFNode,ModelDelta>();
TCFModelProxy(TCFModel model) {
this.model = model;
@@ -31,4 +39,27 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy {
model.onProxyDisposed(this);
super.dispose();
}
+
+ ModelDelta getDelta(TCFNode node) {
+ return deltas.get(node);
+ }
+
+ void addDelta(TCFNode node, ModelDelta delta) {
+ assert deltas.get(node) == null;
+ assert delta.getElement() == node || delta.getElement() == model.getLaunch() && node == model.getRootNode();
+ deltas.put(node, delta);
+ }
+
+ void fireModelChanged() {
+ assert Protocol.isDispatchThread();
+ ModelDelta delta = deltas.get(model.getRootNode());
+ assert (delta == null) == deltas.isEmpty();
+ if (delta != null) {
+ deltas.clear();
+ assert delta.getElement() == model.getLaunch();
+ IModelDelta top = delta.getParentDelta();
+ assert top.getElement() == DebugPlugin.getDefault().getLaunchManager();
+ fireModelChanged(top);
+ }
+ }
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
index f7d4d86e9..861e91057 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
@@ -10,22 +10,11 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.model;
-import java.net.URL;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.eclipse.core.runtime.FileLocator;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.Status;
-import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
-import org.eclipse.debug.core.model.IMemoryBlock;
-import org.eclipse.debug.core.model.IMemoryBlockExtension;
-import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
@@ -35,21 +24,19 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdat
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.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.swt.graphics.RGB;
-import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
+import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IMemory;
import org.eclipse.tm.tcf.services.IRunControl;
-import org.osgi.framework.Bundle;
/**
* TCFNode is base class for all TCF debug model elements.
*/
-public abstract class TCFNode extends PlatformObject
-implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
+public abstract class TCFNode extends PlatformObject implements Comparable<TCFNode> {
protected final String id;
protected final TCFNode parent;
@@ -152,6 +139,10 @@ implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
public String getAddress() {
return null;
}
+
+ boolean isNodeContentVisibleInContext(IPresentationContext p) {
+ return true;
+ }
/**
* Retrieve children count for a presentation context.
@@ -160,7 +151,8 @@ implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
final void update(final IChildrenCountUpdate result) {
new TCFRunnable(model.getDisplay(), result) {
public void run() {
- if (!disposed && model.getLaunch().getChannel() != null) {
+ IChannel channel = model.getLaunch().getChannel();
+ if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
if (!validateNode(this)) return;
getData(result);
}
@@ -180,7 +172,8 @@ implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
final void update(final IChildrenUpdate result) {
new TCFRunnable(model.getDisplay(), result) {
public void run() {
- if (!disposed && model.getLaunch().getChannel() != null) {
+ IChannel channel = model.getLaunch().getChannel();
+ if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
if (!validateNode(this)) return;
getData(result);
}
@@ -197,7 +190,8 @@ implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
final void update(final IHasChildrenUpdate result) {
new TCFRunnable(model.getDisplay(), result) {
public void run() {
- if (!disposed && model.getLaunch().getChannel() != null) {
+ IChannel channel = model.getLaunch().getChannel();
+ if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
if (!validateNode(this)) return;
getData(result);
}
@@ -217,16 +211,10 @@ implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
final void update(final ILabelUpdate result) {
new TCFRunnable(model.getDisplay(), result) {
public void run() {
- if (!disposed) {
+ IChannel channel = model.getLaunch().getChannel();
+ if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
if (!validateNode(this)) return;
- if (node_error != null) {
- result.setForeground(new RGB(255, 0, 0), 0);
- result.setLabel(node_error.getClass().getName() +
- ": " + node_error.getMessage(), 0);
- }
- else {
- getData(result);
- }
+ getData(result);
}
else {
result.setLabel("...", 0);
@@ -277,23 +265,43 @@ implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
* @param result - label update request.
*/
protected void getData(ILabelUpdate result) {
- result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ result.setImageDescriptor(ImageCache.getImageDescriptor(getImageName()), 0);
result.setLabel(id, 0);
}
/**
- * Create ModelDelta for changes in this node.
+ * Create and post ModelDelta for changes in this node.
+ * @param flags - description of what has changed: IModelDelta.ADDED, IModelDelta.REMOVED, etc.
+ */
+ final void makeModelDelta(int flags) {
+ for (TCFModelProxy p : model.getModelProxyList()) {
+ int f = flags & getRelevantModelDeltaFlags(p.getPresentationContext());
+ if (f != 0) makeModelDelta(p, f);
+ }
+ }
+
+ /**
+ * Return bit set of model delta flags relevant for this node in given presentation context.
+ * Sub-classes are supposed to override this method.
+ * @param p - presentation context
+ * @return bit set of model delta flags
+ */
+ int getRelevantModelDeltaFlags(IPresentationContext p) {
+ return IModelDelta.CONTENT | IModelDelta.STATE;
+ }
+
+ /**
+ * Create and post ModelDelta for changes in this node, relevant for given presentation context.
+ * @param p - target presentation context.
* @param flags - description of what has changed: IModelDelta.ADDED, IModelDelta.REMOVED, etc.
* @return - ModelDelta that describes node changes.
*/
- ModelDelta makeModelDelta(int flags) {
- int count = -1;
- int index = -1;
- ModelDelta delta = model.getDelta(this);
- if (delta == null || delta.getChildCount() != count || delta.getIndex() != index) {
- ModelDelta parent_delta = parent.makeModelDelta(IModelDelta.NO_CHANGE);
- delta = parent_delta.addNode(this, index, flags, count);
- model.addDelta(this, delta);
+ ModelDelta makeModelDelta(TCFModelProxy p, int flags) {
+ ModelDelta delta = p.getDelta(this);
+ if (delta == null) {
+ ModelDelta parent_delta = parent.makeModelDelta(p, IModelDelta.NO_CHANGE);
+ delta = parent_delta.addNode(this, flags);
+ p.addDelta(this, delta);
}
else {
delta.setFlags(delta.getFlags() | flags);
@@ -303,185 +311,50 @@ implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
/*--------------------------------------------------------------------------------------*/
/* Node data retrieval state machine */
-
- protected Throwable node_error;
- protected IToken pending_command;
- private final Collection<TCFRunnable> wait_list = new ArrayList<TCFRunnable>();
/**
* Invalidate the node - flush all cached data.
* Subclasses should override this method to flush any additional data.
- * Subclasses should call super.invalidateNode().
- */
- public void invalidateNode() {
- // cancel current data retrieval command
- if (pending_command != null) {
- pending_command.cancel();
- pending_command = null;
- }
-
- // cancel waiting monitors
- if (!wait_list.isEmpty()) {
- for (TCFRunnable r : wait_list) r.cancel();
- wait_list.clear();
- }
-
- node_error = null;
- }
-
- /**
- * Validate node - retrieve and put into a cache missing data from remote peer.
- * Validation is done asynchronously. If the node is already valid,
- * the method should return true. Otherwise, it returns false,
- * and later, when the node becomes valid, call-backs from 'wait_list' are invoked.
- * @return true if the node is already valid, false if validation is started.
*/
- public final boolean validateNode() {
- assert Protocol.isDispatchThread();
- assert !disposed;
- if (pending_command != null) {
- return false;
- }
- else if (model.getLaunch().getChannel() == null) {
- node_error = null;
- }
- else if (node_error == null && !validateNodeData()) {
- return false;
- }
- if (!wait_list.isEmpty()) {
- Runnable[] arr = wait_list.toArray(new Runnable[wait_list.size()]);
- wait_list.clear();
- for (Runnable r : arr) r.run();
- }
- return true;
- }
+ public abstract void invalidateNode();
/**
* Validate node - retrieve and put into a cache missing data from remote peer.
+ * The method should initiate retrieval of all data needed by TCFNode.update() methods.
* Validation is done asynchronously. If the node is already valid,
* the method should return true. Otherwise, it returns false,
- * adds 'done' into 'wait_list', and later, when the node becomes valid,
- * call-backs from 'wait_list' are invoked.
- * @param done - call-back object to call when node becomes valid.
+ * adds 'done' into 'wait_list', and later call-backs from 'wait_list' are invoked.
+ * Note: activation of call-back does not mean all data is retrieved,
+ * it only means that node state changed, client should call validateNode() again,
+ * until the method returns true.
+ * @param done - call-back object to call when node state changes.
* @return true if the node is already valid, false if validation is started.
*/
- public final boolean validateNode(TCFRunnable done) {
- assert done != null;
- if (!validateNode()) {
- wait_list.add(done);
- return false;
- }
- return true;
- }
+ public abstract boolean validateNode(Runnable done);
- private class ValidateNodes extends TCFRunnable {
-
- int cnt = 0;
- private IToken command;
-
- ValidateNodes(Collection<TCFNode> nodes) {
- for (TCFNode n : nodes) {
- if (!n.validateNode(this)) cnt++;
- }
- if (cnt > 0) {
- pending_command = command = new IToken() {
- public boolean cancel() {
- return false;
- }
- };
- }
- }
-
- public void run() {
- cnt--;
- assert cnt >= 0;
- if (cnt != 0) return;
- if (command != pending_command) return;
- Protocol.invokeLater(new Runnable() {
- public void run() {
- if (command != pending_command) return;
- pending_command = null;
- validateNode();
- }
- });
- }
-
- @Override
- public void cancel() {
- run();
- }
- }
-
/**
* Subclasses can use this method to validate a collection of nodes.
* Validation of multiple nodes is expensive and should be avoided
* when possible.
*
- * Validation is performed in background, and call-backs from 'wait_list' are
- * activated when validation is done.
+ * Validation is performed in background, and 'done' call-back is
+ * activated when nodes state changes.
*
* @param nodes
* @return true if all nodes are already valid, false if validation is started.
*/
- protected boolean validateNodes(Collection<TCFNode> nodes) {
- if (nodes.isEmpty()) return true;
- if (pending_command != null) return false;
- return new ValidateNodes(nodes).cnt == 0;
- }
-
- /**
- * Subclasses should override this method to implement data retrieval that
- * is specific for this node.
- *
- * Data retrieval should be performed in background, and it should call
- * validateNode() when retrieval is done.
- *
- * @return true if the node is already valid, false if data retrieval is started.
- */
- protected abstract boolean validateNodeData();
-
- /*--------------------------------------------------------------------------------------*/
- /* Memory Block Retrieval */
-
- public IMemoryBlockExtension getExtendedMemoryBlock(String addr, Object ctx) throws DebugException {
- assert ctx == this;
- return getMemoryBlock(addr, 0);
- }
-
- public IMemoryBlock getMemoryBlock(long addr, long length) throws DebugException {
- return getMemoryBlock(Long.toString(addr), length);
- }
-
- public boolean supportsStorageRetrieval() {
- return getMemoryContext() != null;
- }
-
- private IMemoryBlockExtension getMemoryBlock(String addr, long length) throws DebugException {
- assert !Protocol.isDispatchThread();
- // TODO: MemoryBlock
- return null;
+ protected boolean validateNodes(Collection<TCFNode> nodes, Runnable done) {
+ TCFNode pending = null;
+ for (TCFNode n : nodes) {
+ if (!n.validateNode(null)) pending = n;
+ }
+ if (pending != null && !pending.validateNode(done)) return false;
+ return true;
}
-
+
/*--------------------------------------------------------------------------------------*/
/* Misc */
- private static final Map<String,ImageDescriptor> image_cache = new HashMap<String,ImageDescriptor>();
-
- static ImageDescriptor getImageDescriptor(String name) {
- if (name == null) return null;
- ImageDescriptor descriptor = image_cache.get(name);
- if (descriptor == null) {
- descriptor = ImageDescriptor.getMissingImageDescriptor();
- Bundle bundle = Platform.getBundle("org.eclipse.debug.ui");
- if (bundle != null){
- URL url = FileLocator.find(bundle, new Path(name), null);
- descriptor = ImageDescriptor.createFromURL(url);
- }
- image_cache.put(name, descriptor);
- }
- return descriptor;
- }
-
protected String getImageName() {
return null;
}
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 db2f09164..3e27e700b 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
@@ -10,7 +10,9 @@
*******************************************************************************/
package org.eclipse.tm.internal.tcf.debug.ui.model;
+import java.math.BigInteger;
import java.util.Arrays;
+import java.util.LinkedHashMap;
import java.util.Map;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
@@ -18,44 +20,109 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
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.ModelDelta;
import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
+import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IMemory;
import org.eclipse.tm.tcf.services.IRunControl;
+@SuppressWarnings("serial")
public class TCFNodeExecContext extends TCFNode {
private final TCFChildrenExecContext children_exec;
private final TCFChildrenStackTrace children_stack;
private final TCFChildrenRegisters children_regs;
- private IMemory.MemoryContext mem_context;
- private IRunControl.RunControlContext run_context;
+ private final TCFDataCache<IMemory.MemoryContext> mem_context;
+ private final TCFDataCache<IRunControl.RunControlContext> run_context;
+ private final TCFDataCache<ContextState> state;
- private boolean suspended;
- private String suspended_pc;
- private String suspended_reason;
- @SuppressWarnings("unused")
- private Map<String,Object> suspended_params;
- private boolean running;
- private boolean terminated;
- @SuppressWarnings("unused")
- private String exception_msg;
+ private final Map<BigInteger,TCFSourceRef> line_info_cache;
- private boolean valid_mem_ctx;
- private boolean valid_run_ctx;
- private boolean valid_state;
+ private static class ContextState {
+ boolean suspended;
+ String suspended_pc;
+ String suspended_reason;
+ boolean terminated;
+ }
private int resumed_cnt;
- TCFNodeExecContext(TCFNode parent, String id) {
+ TCFNodeExecContext(TCFNode parent, final String id) {
super(parent, id);
children_exec = new TCFChildrenExecContext(this);
children_regs = new TCFChildrenRegisters(this);
children_stack = new TCFChildrenStackTrace(this, children_regs);
+ line_info_cache = new LinkedHashMap<BigInteger,TCFSourceRef>() {
+ @SuppressWarnings("unchecked")
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > 256;
+ }
+ };
+ IChannel channel = model.getLaunch().getChannel();
+ mem_context = new TCFDataCache<IMemory.MemoryContext>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ assert command == null;
+ IMemory mem = model.getLaunch().getService(IMemory.class);
+ if (mem == null) {
+ set(null, null, null);
+ return true;
+ }
+ command = mem.getContext(id, new IMemory.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IMemory.MemoryContext context) {
+ set(token, error, context);
+ }
+ });
+ return false;
+ }
+ };
+ run_context = new TCFDataCache<IRunControl.RunControlContext>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ assert command == null;
+ IRunControl run = model.getLaunch().getService(IRunControl.class);
+ if (run == null) {
+ set(null, null, null);
+ return true;
+ }
+ command = run.getContext(id, new IRunControl.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IRunControl.RunControlContext context) {
+ set(token, error, context);
+ }
+ });
+ return false;
+ }
+ };
+ state = new TCFDataCache<ContextState>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ assert command == null;
+ if (!run_context.validate()) {
+ run_context.wait(this);
+ return false;
+ }
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx == null || !ctx.hasState()) {
+ set(null, null, null);
+ return true;
+ }
+ 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;
+ set(token, error, s);
+ }
+ });
+ return false;
+ }
+ };
}
@Override
@@ -73,49 +140,70 @@ public class TCFNodeExecContext extends TCFNode {
children_regs.dispose(id);
}
- void setRunContext(IRunControl.RunControlContext ctx) {
- run_context = ctx;
- valid_run_ctx = true;
+ void setRunContext(IRunControl.RunControlContext ctx) {
+ run_context.reset(ctx);
}
void setMemoryContext(IMemory.MemoryContext ctx) {
- mem_context = ctx;
- valid_mem_ctx = true;
+ mem_context.reset(ctx);
+ }
+
+ Map<BigInteger,TCFSourceRef> getLineInfoCache() {
+ return line_info_cache;
}
@Override
public IRunControl.RunControlContext getRunContext() {
assert Protocol.isDispatchThread();
- return run_context;
+ if (!run_context.isValid()) return null;
+ return run_context.getData();
}
@Override
public IMemory.MemoryContext getMemoryContext() {
assert Protocol.isDispatchThread();
- return mem_context;
+ if (!mem_context.isValid()) return null;
+ return mem_context.getData();
}
@Override
public boolean isRunning() {
assert Protocol.isDispatchThread();
- return running;
+ if (!run_context.isValid()) return false;
+ 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;
}
@Override
public boolean isSuspended() {
assert Protocol.isDispatchThread();
- return suspended;
+ if (!run_context.isValid()) return false;
+ 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;
}
@Override
public String getAddress() {
assert Protocol.isDispatchThread();
- return suspended_pc;
+ if (!run_context.isValid()) return null;
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx == null || !ctx.hasState()) return null;
+ if (!state.isValid()) return null;
+ ContextState s = state.getData();
+ if (s == null) return null;
+ return s.suspended_pc;
}
@Override
protected void getData(IChildrenCountUpdate result) {
- if (run_context != null && run_context.hasState()) {
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx != null && ctx.hasState()) {
if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
result.setChildCount(children_regs.size());
}
@@ -132,7 +220,8 @@ public class TCFNodeExecContext extends TCFNode {
protected void getData(IChildrenUpdate result) {
int offset = 0;
TCFNode[] arr = null;
- if (run_context != null && run_context.hasState()) {
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx != null && ctx.hasState()) {
if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
arr = children_regs.toArray();
}
@@ -154,7 +243,8 @@ public class TCFNodeExecContext extends TCFNode {
@Override
protected void getData(IHasChildrenUpdate result) {
- if (run_context != null && run_context.hasState()) {
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx != null && ctx.hasState()) {
if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
result.setHasChilren(children_regs.size() > 0);
}
@@ -169,43 +259,42 @@ public class TCFNodeExecContext extends TCFNode {
@Override
protected void getData(ILabelUpdate result) {
- result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ result.setImageDescriptor(ImageCache.getImageDescriptor(getImageName()), 0);
String label = id;
- if (run_context != null) {
- if (run_context.hasState()) {
- if (running) {
+ Throwable error = run_context.getError();
+ if (error != null) {
+ result.setForeground(new RGB(255, 0, 0), 0);
+ label += ": " + error.getClass().getName() + ": " + error.getMessage();
+ }
+ else {
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx != null) {
+ if (isRunning()) {
label += " (Running)";
}
- else if (suspended) {
- if (suspended_reason != null) {
- label += " (" + suspended_reason + ")";
+ else if (isSuspended()) {
+ String r = state.getData().suspended_reason;
+ if (r != null) {
+ label += " (" + r + ")";
}
else {
label += " (Suspended)";
}
}
+ String file = (String)ctx.getProperties().get("File");
+ if (file != null) label += " " + file;
}
- String file = (String)run_context.getProperties().get("File");
- if (file != null) label += " " + file;
}
result.setLabel(label, 0);
}
- @Override
- ModelDelta makeModelDelta(int flags) {
- if (run_context != null && run_context.isContainer()) flags |= IModelDelta.STATE;
- return super.makeModelDelta(flags);
- }
-
void onContextAdded(IRunControl.RunControlContext context) {
children_exec.onContextAdded(context);
}
void onContextChanged(IRunControl.RunControlContext context) {
assert !disposed;
- if (!valid_run_ctx) invalidateNode();
- run_context = context;
- valid_run_ctx = true;
+ run_context.reset(context);
resumed_cnt++;
children_stack.onSourceMappingChange();
makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
@@ -217,9 +306,7 @@ public class TCFNodeExecContext extends TCFNode {
void onContextChanged(IMemory.MemoryContext context) {
assert !disposed;
- if (!valid_mem_ctx) invalidateNode();
- mem_context = context;
- valid_mem_ctx = true;
+ mem_context.reset(context);
resumed_cnt++;
makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
@@ -228,104 +315,70 @@ public class TCFNodeExecContext extends TCFNode {
assert !disposed;
resumed_cnt++;
dispose();
- if (parent instanceof TCFNodeExecContext &&
- ((TCFNodeExecContext)parent).children_exec.valid) {
- makeModelDelta(IModelDelta.REMOVED);
- }
- else {
- parent.invalidateNode();
- parent.makeModelDelta(IModelDelta.CONTENT);
- }
+ parent.makeModelDelta(IModelDelta.CONTENT);
}
void onContainerSuspended() {
assert !disposed;
- if (valid_run_ctx) {
- if (run_context == null) return;
- if (!run_context.hasState()) return;
- suspended = false;
- running = false;
- valid_state = false;
- super.invalidateNode();
- children_stack.onSuspended();
- }
- else {
- invalidateNode();
+ if (run_context.isValid()) {
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx == null) return;
+ if (!ctx.hasState()) return;
}
+ state.reset();
+ children_stack.onSuspended();
makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
void onContainerResumed() {
assert !disposed;
- if (valid_run_ctx) {
- if (run_context == null) return;
- if (!run_context.hasState()) return;
- suspended = false;
- running = false;
- valid_state = false;
- super.invalidateNode();
- children_stack.onResumed();
- }
- else {
- invalidateNode();
+ if (run_context.isValid()) {
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx == null) return;
+ if (!ctx.hasState()) return;
}
+ state.reset();
makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
void onContextSuspended(String pc, String reason, Map<String,Object> params) {
assert !disposed;
- if (valid_run_ctx) {
- if (run_context == null) return;
- if (!run_context.hasState()) return;
- super.invalidateNode();
- children_stack.onSuspended();
- suspended = true;
- suspended_pc = pc;
- suspended_reason = reason;
- suspended_params = params;
- running = false;
- valid_state = true;
- }
- else {
- invalidateNode();
- }
+ ContextState s = new ContextState();
+ s.suspended = true;
+ s.suspended_pc = pc;
+ s.suspended_reason = reason;
+ state.reset(s);
+ children_stack.onSuspended();
resumed_cnt++;
makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
void onContextResumed() {
assert !disposed;
- if (valid_run_ctx) {
- if (run_context == null) return;
- if (!run_context.hasState()) return;
- super.invalidateNode();
- exception_msg = null;
- terminated = false;
- suspended = false;
- suspended_pc = null;
- suspended_reason = null;
- suspended_params = null;
- running = true;
- valid_state = true;
- }
- else {
- invalidateNode();
- }
- makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ state.reset(new ContextState());
+ makeModelDelta(IModelDelta.STATE);
final int cnt = ++resumed_cnt;
model.invokeLater(250, new Runnable() {
public void run() {
if (cnt != resumed_cnt) return;
+ if (disposed) return;
children_stack.onResumed();
+ if (!validateNode(this)) return;
makeModelDelta(IModelDelta.CONTENT);
+ if (parent instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)parent).onChildResumedOrSuspended();
+ }
}
});
}
+
+ void onChildResumedOrSuspended() {
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx != null && ctx.isContainer()) makeModelDelta(IModelDelta.STATE);
+ if (parent instanceof TCFNodeExecContext) ((TCFNodeExecContext)parent).onChildResumedOrSuspended();
+ }
void onContextException(String msg) {
- assert !disposed;
- exception_msg = msg;
- makeModelDelta(IModelDelta.STATE);
}
void onMemoryChanged(Number[] addr, long[] size) {
@@ -333,157 +386,117 @@ public class TCFNodeExecContext extends TCFNode {
}
void onRegistersChanged() {
- super.invalidateNode();
- children_regs.invalidate();
+ children_stack.onRegistersChanged();
makeModelDelta(IModelDelta.CONTENT);
}
@Override
public void invalidateNode() {
- super.invalidateNode();
- valid_mem_ctx = false;
- valid_run_ctx = false;
- valid_state = false;
- running = false;
- suspended = false;
- children_exec.invalidate();
- children_stack.invalidate();
- children_regs.invalidate();
+ run_context.reset();
+ mem_context.reset();
+ state.reset();
+ children_exec.reset();
+ children_stack.reset();
+ children_regs.reset();
}
@Override
- protected boolean validateNodeData() {
+ public boolean validateNode(Runnable done) {
assert !disposed;
- if (!valid_mem_ctx && !validateMemoryContext()) return false;
- if (!valid_run_ctx && !validateRunControlContext()) return false;
- if (!valid_state && !validateRunControlState()) return false;
- if (!children_stack.valid && !children_stack.validate()) return false;
- if (!children_regs.valid && !children_regs.validate()) return false;
- if (!children_exec.valid && !children_exec.validate()) return false;
- if (run_context != null && !run_context.hasState()) {
- // Container need to validate children for hasSuspendedChildren() method
- // to return valid value.
- if (!validateNodes(children_exec.children.values())) return false;
+ mem_context.validate();
+ run_context.validate();
+ if (!mem_context.isValid()) {
+ mem_context.wait(done);
+ return false;
}
- return true;
- }
-
- private boolean validateMemoryContext() {
- assert pending_command == null;
- IMemory mem = model.getLaunch().getService(IMemory.class);
- if (mem == null) {
- valid_mem_ctx = true;
- return true;
+ if (!run_context.isValid()) {
+ run_context.wait(done);
+ return false;
}
- pending_command = mem.getContext(id, new IMemory.DoneGetContext() {
- public void doneGetContext(IToken token, Exception error, IMemory.MemoryContext context) {
- if (pending_command != token) return;
- pending_command = null;
- if (error != null) {
- node_error = error;
- }
- else {
- mem_context = context;
- }
- valid_mem_ctx = true;
- validateNode();
- }
- });
- return false;
- }
-
- private boolean validateRunControlContext() {
- assert pending_command == null;
- IRunControl run = model.getLaunch().getService(IRunControl.class);
- if (run == null) {
- valid_run_ctx = true;
- return true;
+ state.validate();
+ children_exec.validate();
+ if (!state.isValid()) {
+ state.wait(done);
+ return false;
}
- pending_command = run.getContext(id, new IRunControl.DoneGetContext() {
- public void doneGetContext(IToken token, Exception error, IRunControl.RunControlContext context) {
- if (pending_command != token) return;
- pending_command = null;
- if (error != null) {
- node_error = error;
- }
- else {
- run_context = context;
- }
- valid_run_ctx = true;
- validateNode();
+ if (!children_exec.isValid()) {
+ children_exec.wait(done);
+ return false;
+ }
+ children_regs.validate();
+ children_stack.validate();
+
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx != null && !ctx.hasState()) {
+ // Container need to validate children for
+ // hasSuspendedChildren() method to return valid value.
+ TCFDataCache<?> dt = validateChildrenState();
+ if (dt != null) {
+ dt.wait(done);
+ return false;
}
- });
- return false;
- }
-
- private boolean validateRunControlState() {
- assert pending_command == null;
- if (node_error != null || run_context == null || !run_context.hasState()) {
- suspended = false;
- suspended_pc = null;
- suspended_reason = null;
- suspended_params = null;
- running = false;
- valid_state = true;
- return true;
}
- pending_command = run_context.getState(new IRunControl.DoneGetState() {
- public void doneGetState(IToken token, Exception error, boolean suspend, String pc, String reason, Map<String,Object> params) {
- if (token != pending_command) return;
- pending_command = null;
- if (error != null) {
- suspended = false;
- suspended_pc = null;
- suspended_reason = null;
- suspended_params = null;
- node_error = error;
- running = false;
- }
- else {
- suspended = suspend;
- if (suspend) {
- suspended_pc = pc;
- suspended_reason = reason;
- suspended_params = params;
- }
- else {
- suspended_pc = null;
- suspended_reason = null;
- suspended_params = null;
- }
- running = !suspend;
- }
- valid_state = true;
- validateNode();
+
+ if (!children_regs.isValid()) {
+ children_regs.wait(done);
+ return false;
+ }
+ if (!children_stack.isValid()) {
+ children_stack.wait(done);
+ return false;
+ }
+ return true;
+ }
+
+ // Validate children state for hasSuspendedChildren()
+ // Return TCFDataCache to wait for if validation is pending.
+ private TCFDataCache<?> validateChildrenState() {
+ if (!children_exec.validate()) return children_exec;
+ TCFDataCache<?> pending = null;
+ for (TCFNode n : children_exec.getData().values()) {
+ if (!(n instanceof TCFNodeExecContext)) continue;
+ TCFNodeExecContext e = (TCFNodeExecContext)n;
+ if (!e.run_context.validate()) {
+ pending = e.run_context;
+ continue;
}
- });
- return false;
+ IRunControl.RunControlContext ctx = e.run_context.getData();
+ if (ctx == null) continue;
+ if (ctx.hasState() && !e.state.validate()) pending = e.state;
+ if (ctx.isContainer()) pending = e.validateChildrenState();
+ }
+ return pending;
}
+ // Return true if at least one child is suspended
+ // The method will fail if node is not validated, see validateChildrenState()
private boolean hasSuspendedChildren() {
- for (TCFNode n : children_exec.children.values()) {
- if (n instanceof TCFNodeExecContext) {
- TCFNodeExecContext e = (TCFNodeExecContext)n;
- if (e.run_context != null) {
- if (e.run_context.hasState() && e.suspended) return true;
- if (e.run_context.isContainer() && e.hasSuspendedChildren()) return true;
- }
- }
+ Map<String,TCFNode> m = children_exec.getData();
+ if (m == null) return false;
+ for (TCFNode n : m.values()) {
+ if (!(n instanceof TCFNodeExecContext)) continue;
+ TCFNodeExecContext e = (TCFNodeExecContext)n;
+ IRunControl.RunControlContext ctx = e.run_context.getData();
+ if (ctx == null) continue;
+ if (ctx.hasState() && e.isSuspended()) return true;
+ if (ctx.isContainer() && e.hasSuspendedChildren()) return true;
}
return false;
}
@Override
protected String getImageName() {
- if (run_context != null && run_context.hasState()) {
+ IRunControl.RunControlContext ctx = run_context.getData();
+ if (ctx != null && ctx.hasState()) {
// Thread
- if (terminated) return "icons/full/obj16/threadt_obj.gif";
- if (suspended) return "icons/full/obj16/threads_obj.gif";
+ ContextState s = state.getData();
+ if (s != null && s.terminated) return "icons/full/obj16/threadt_obj.gif";
+ if (s != null && s.suspended) return "icons/full/obj16/threads_obj.gif";
return "icons/full/obj16/thread_obj.gif";
}
- else if (run_context != null) {
+ else if (ctx != null) {
// Thread container (process)
- if (terminated) return "icons/full/obj16/debugtt_obj.gif";
+ //if (terminated) return "icons/full/obj16/debugtt_obj.gif";
if (hasSuspendedChildren()) return "icons/full/obj16/debugts_obj.gif";
return "icons/full/obj16/debugt_obj.gif";
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java
index 5e7b8bf65..6b767821d 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java
@@ -16,11 +16,8 @@ import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
-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.ModelDelta;
-import org.eclipse.swt.graphics.RGB;
-import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
import org.eclipse.tm.tcf.services.IMemory;
import org.eclipse.tm.tcf.services.IRunControl;
@@ -67,26 +64,7 @@ public class TCFNodeLaunch extends TCFNode {
protected void getData(IHasChildrenUpdate result) {
result.setHasChilren(children.size() > 0);
}
-
- @Override
- protected void getData(ILabelUpdate result) {
- result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
- String label = id;
- TCFLaunch launch = model.getLaunch();
- String status = "";
- if (launch.isConnecting()) status = "Connecting";
- else if (launch.isDisconnected()) status = "Disconnected";
- else if (launch.isTerminated()) status = "Terminated";
- Throwable error = launch.getError();
- if (error != null) {
- status += " - " + error;
- result.setForeground(new RGB(255, 0, 0), 0);
- }
- if (status.length() > 0) status = " (" + status + ")";
- label = launch.getLaunchConfiguration().getName() + status;
- result.setLabel(label, 0);
- }
-
+
void onContextAdded(IRunControl.RunControlContext context) {
children.onContextAdded(context);
}
@@ -96,16 +74,14 @@ public class TCFNodeLaunch extends TCFNode {
}
@Override
- ModelDelta makeModelDelta(int flags) {
- int count = -1;
- ModelDelta delta = model.getDelta(this);
+ ModelDelta makeModelDelta(TCFModelProxy p, int flags) {
+ ModelDelta delta = p.getDelta(this);
if (delta == null) {
delta = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
- delta = delta.addNode(model.getLaunch(), -1, flags, count);
- model.addDelta(this, delta);
+ delta = delta.addNode(model.getLaunch(), -1, flags, -1);
+ p.addDelta(this, delta);
}
else {
- assert delta.getChildCount() == count;
delta.setFlags(delta.getFlags() | flags);
}
return delta;
@@ -113,18 +89,15 @@ public class TCFNodeLaunch extends TCFNode {
@Override
public void invalidateNode() {
- super.invalidateNode();
- children.invalidate();
+ children.reset();
}
@Override
- protected boolean validateNodeData() {
- if (!children.valid && !children.validate()) return false;
+ public boolean validateNode(Runnable done) {
+ if (!children.validate()) {
+ children.wait(done);
+ return false;
+ }
return true;
}
-
- @Override
- protected String getImageName() {
- return "icons/full/obj16/ldebug_obj.gif";
- }
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java
index 748bd7280..575d3ea14 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java
@@ -12,6 +12,11 @@ package org.eclipse.tm.internal.tcf.debug.ui.model;
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.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
+import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.services.IRegisters;
@@ -37,41 +42,114 @@ public class TCFNodeRegister extends TCFNode {
COL_MNEMONIC = "Menimonic";
- private IRegisters.RegistersContext context;
- private String hex_value;
- private String dec_value;
- private Number num_value;
- private boolean valid_context;
- private boolean valid_hex_value;
- private boolean valid_dec_value;
+ private final TCFDataCache<IRegisters.RegistersContext> context;
+ private final TCFDataCache<String> hex_value;
+ private final TCFDataCache<String> dec_value;
- TCFNodeRegister(TCFNode parent, String id) {
+ TCFNodeRegister(TCFNode parent, final String id) {
super(parent, id);
+ IChannel channel = parent.model.getLaunch().getChannel();
+ context = new TCFDataCache<IRegisters.RegistersContext>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ IRegisters regs = model.getLaunch().getService(IRegisters.class);
+ command = regs.getContext(id, new IRegisters.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IRegisters.RegistersContext context) {
+ set(token, error, context);
+ }
+ });
+ return false;
+ }
+ };
+ hex_value = new TCFDataCache<String>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ if (!context.validate()) {
+ context.wait(this);
+ return false;
+ }
+ IRegisters.RegistersContext ctx = context.getData();
+ if (ctx == null) {
+ set(null, null, null);
+ return true;
+ }
+ String[] fmts = ctx.getAvailableFormats();
+ String fmt = null;
+ for (String s : fmts) {
+ if (s.equals(IRegisters.FORMAT_HEX)) fmt = s;
+ }
+ if (fmt == null) {
+ set(null, null, null);
+ return true;
+ }
+ command = ctx.get(fmt, new IRegisters.DoneGet() {
+ public void doneGet(IToken token, Exception error, String value) {
+ set(token, error, value);
+ }
+ });
+ return false;
+ }
+ };
+ dec_value = new TCFDataCache<String>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ if (!context.validate()) {
+ context.wait(this);
+ return false;
+ }
+ IRegisters.RegistersContext ctx = context.getData();
+ if (ctx == null) {
+ set(null, null, null);
+ return true;
+ }
+ String[] fmts = ctx.getAvailableFormats();
+ String fmt = null;
+ for (String s : fmts) {
+ if (s.equals(IRegisters.FORMAT_DECIMAL)) fmt = s;
+ }
+ if (fmt == null) {
+ set(null, null, null);
+ return true;
+ }
+ command = ctx.get(fmt, new IRegisters.DoneGet() {
+ public void doneGet(IToken token, Exception error, String value) {
+ set(token, error, value);
+ }
+ });
+ return false;
+ }
+ };
}
@Override
protected void getData(ILabelUpdate result) {
- result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
- if (context != null) {
+ result.setImageDescriptor(ImageCache.getImageDescriptor(getImageName()), 0);
+ IRegisters.RegistersContext ctx = context.getData();
+ Throwable error = context.getError();
+ if (error != null) {
+ result.setForeground(new RGB(255, 0, 0), 0);
+ result.setLabel(id + ": " + error.getClass().getName() + ": " + error.getMessage(), 0);
+ }
+ else if (ctx != null) {
String[] cols = result.getColumnIds();
if (cols == null) {
- result.setLabel(context.getName() + " = " + hex_value, 0);
+ result.setLabel(ctx.getName() + " = " + hex_value.getData(), 0);
}
else {
for (int i = 0; i < cols.length; i++) {
String c = cols[i];
- if (c.equals(COL_NAME)) result.setLabel(context.getName(), i);
- else if (c.equals(COL_HEX_VALUE)) result.setLabel(hex_value, i);
- else if (c.equals(COL_DEC_VALUE)) result.setLabel(dec_value, i);
- else if (c.equals(COL_DESCRIPTION)) result.setLabel(context.getDescription(), i);
- else if (c.equals(COL_READBLE)) result.setLabel(bool(context.isReadable()), i);
- else if (c.equals(COL_READ_ONCE)) result.setLabel(bool(context.isReadOnce()), i);
- else if (c.equals(COL_WRITEABLE)) result.setLabel(bool(context.isWriteable()), i);
- else if (c.equals(COL_WRITE_ONCE)) result.setLabel(bool(context.isWriteOnce()), i);
- else if (c.equals(COL_SIDE_EFFECTS)) result.setLabel(bool(context.hasSideEffects()), i);
- else if (c.equals(COL_VOLATILE)) result.setLabel(bool(context.isVolatile()), i);
- else if (c.equals(COL_FLOAT)) result.setLabel(bool(context.isFloat()), i);
- else if (c.equals(COL_MNEMONIC)) result.setLabel(getMnemonic(), i);
+ if (c.equals(COL_NAME)) result.setLabel(ctx.getName(), i);
+ else if (c.equals(COL_HEX_VALUE)) setLabel(result, hex_value, i);
+ else if (c.equals(COL_DEC_VALUE)) result.setLabel(dec_value.getData(), i);
+ else if (c.equals(COL_DESCRIPTION)) result.setLabel(ctx.getDescription(), i);
+ else if (c.equals(COL_READBLE)) result.setLabel(bool(ctx.isReadable()), i);
+ else if (c.equals(COL_READ_ONCE)) result.setLabel(bool(ctx.isReadOnce()), i);
+ else if (c.equals(COL_WRITEABLE)) result.setLabel(bool(ctx.isWriteable()), i);
+ else if (c.equals(COL_WRITE_ONCE)) result.setLabel(bool(ctx.isWriteOnce()), i);
+ else if (c.equals(COL_SIDE_EFFECTS)) result.setLabel(bool(ctx.hasSideEffects()), i);
+ else if (c.equals(COL_VOLATILE)) result.setLabel(bool(ctx.isVolatile()), i);
+ else if (c.equals(COL_FLOAT)) result.setLabel(bool(ctx.isFloat()), i);
+ else if (c.equals(COL_MNEMONIC)) result.setLabel(getMnemonic(ctx), i);
}
}
}
@@ -79,30 +157,59 @@ public class TCFNodeRegister extends TCFNode {
result.setLabel(id, 0);
}
}
+
+ private void setLabel(ILabelUpdate result, TCFDataCache<String> data, int pos) {
+ Throwable error = data.getError();
+ if (error != null) {
+ result.setForeground(new RGB(255, 0, 0), pos);
+ result.setLabel(error.getClass().getName() + ": " + error.getMessage(), pos);
+ }
+ else if (data.getData() != null) {
+ result.setLabel(data.getData(), pos);
+ }
+ }
private String bool(boolean b) {
return b ? "yes" : "no";
}
- private String getMnemonic() {
- if (num_value != null) {
- IRegisters.NamedValue[] arr = context.getNamedValues();
+ private String getMnemonic(IRegisters.RegistersContext ctx) {
+ if (dec_value.getData() != null) {
+ IRegisters.NamedValue[] arr = ctx.getNamedValues();
if (arr != null) {
- if (context.isFloat()) {
+ if (ctx.isFloat()) {
+ double v = Double.parseDouble(dec_value.getData());
for (IRegisters.NamedValue n : arr) {
- if (n.getValue().doubleValue() == num_value.doubleValue()) return n.getName();
+ if (n.getValue().doubleValue() == v) return n.getName();
}
}
else {
+ long v = Long.parseLong(dec_value.getData());
for (IRegisters.NamedValue n : arr) {
- if (n.getValue().longValue() == num_value.longValue()) return n.getName();
+ if (n.getValue().longValue() == v) return n.getName();
}
}
}
}
+ else if (!ctx.isFloat() && hex_value.getData() != null) {
+ IRegisters.NamedValue[] arr = ctx.getNamedValues();
+ if (arr != null) {
+ long v = Long.parseLong(hex_value.getData(), 16);
+ for (IRegisters.NamedValue n : arr) {
+ if (n.getValue().longValue() == v) return n.getName();
+ }
+ }
+ }
return "";
}
+ int getRelevantModelDeltaFlags(IPresentationContext p) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(p.getId())) {
+ return IModelDelta.CONTENT | IModelDelta.STATE;
+ }
+ return 0;
+ }
+
void onValueChanged() {
onSuspended();
}
@@ -111,111 +218,43 @@ public class TCFNodeRegister extends TCFNode {
* Invalidate register value only, keep cached register attributes.
*/
void onSuspended() {
- super.invalidateNode();
- valid_hex_value = false;
- valid_dec_value = false;
- hex_value = null;
- dec_value = null;
- num_value = null;
+ hex_value.reset();
+ dec_value.reset();
makeModelDelta(IModelDelta.STATE);
}
+
+ void onRegistersChanged() {
+ context.reset();
+ hex_value.reset();
+ dec_value.reset();
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
@Override
public void invalidateNode() {
- super.invalidateNode();
- valid_context = false;
- valid_hex_value = false;
- valid_dec_value = false;
- hex_value = null;
- dec_value = null;
- num_value = null;
+ context.reset();
+ hex_value.reset();
+ dec_value.reset();
}
@Override
- protected boolean validateNodeData() {
- if (!valid_context && !validateRegisterContext()) return false;
- if (!valid_hex_value && !validateRegisterHexValue()) return false;
- if (!valid_dec_value && !validateRegisterDecValue()) return false;
- return true;
- }
-
- private boolean validateRegisterContext() {
- assert pending_command == null;
- IRegisters regs = model.getLaunch().getService(IRegisters.class);
- pending_command = regs.getContext(id, new IRegisters.DoneGetContext() {
- public void doneGetContext(IToken token, Exception error, IRegisters.RegistersContext context) {
- if (pending_command != token) return;
- pending_command = null;
- if (error != null) {
- node_error = error;
- }
- else {
- TCFNodeRegister.this.context = context;
- }
- valid_context = true;
- validateNode();
- }
- });
- return false;
- }
-
- private boolean validateRegisterHexValue() {
- assert pending_command == null;
- String[] fmts = context.getAvailableFormats();
- String fmt = null;
- for (String s : fmts) {
- if (s.equals(IRegisters.FORMAT_HEX)) fmt = s;
+ public boolean validateNode(Runnable done) {
+ boolean ctx_valid = context.validate();
+ boolean dec_valid = dec_value.validate();
+ boolean hex_valid = hex_value.validate();
+ if (!ctx_valid) {
+ if (done != null) context.wait(done);
+ return false;
}
- if (fmt == null) {
- valid_hex_value = true;
- return true;
+ if (!dec_valid) {
+ if (done != null) dec_value.wait(done);
+ return false;
}
- pending_command = context.get(fmt, new IRegisters.DoneGet() {
- public void doneGet(IToken token, Exception error, String value) {
- if (pending_command != token) return;
- pending_command = null;
- if (error != null) {
- node_error = error;
- }
- else {
- hex_value = value;
- if (!context.isFloat()) num_value = Long.valueOf(value, 16);
- }
- valid_hex_value = true;
- validateNode();
- }
- });
- return false;
- }
-
- private boolean validateRegisterDecValue() {
- assert pending_command == null;
- String[] fmts = context.getAvailableFormats();
- String fmt = null;
- for (String s : fmts) {
- if (s.equals(IRegisters.FORMAT_DECIMAL)) fmt = s;
- }
- if (fmt == null) {
- valid_dec_value = true;
- return true;
+ if (!hex_valid) {
+ if (done != null) hex_value.wait(done);
+ return false;
}
- pending_command = context.get(fmt, new IRegisters.DoneGet() {
- public void doneGet(IToken token, Exception error, String value) {
- if (pending_command != token) return;
- pending_command = null;
- if (error != null) {
- node_error = error;
- }
- else {
- dec_value = value;
- if (!context.isFloat()) num_value = Long.valueOf(value, 10);
- else num_value = Double.valueOf(value);
- }
- valid_dec_value = true;
- validateNode();
- }
- });
- return false;
+ return true;
}
@Override
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 41928e60b..71c037ed2 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
@@ -11,8 +11,8 @@
package org.eclipse.tm.internal.tcf.debug.ui.model;
import java.math.BigInteger;
-import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Map;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
@@ -20,6 +20,9 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdat
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.ui.ImageCache;
+import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.ILineNumbers;
@@ -28,31 +31,108 @@ import org.eclipse.tm.tcf.services.IRunControl;
import org.eclipse.tm.tcf.services.IStackTrace;
import org.eclipse.tm.tcf.services.ILineNumbers.CodeArea;
-
+@SuppressWarnings("serial")
public class TCFNodeStackFrame extends TCFNode {
- private IStackTrace.StackTraceContext stack_trace_context;
- private ILineNumbers.CodeArea code_area;
- private BigInteger code_address;
-
- private final int frame_no;
+ private int frame_no;
private final TCFChildrenRegisters children_regs;
-
- TCFNodeStackFrame(TCFNode parent, String id, TCFChildrenRegisters children_regs) {
+ private final TCFDataCache<IStackTrace.StackTraceContext> stack_trace_context;
+ private final TCFDataCache<TCFSourceRef> line_info;
+
+ private TCFNodeStackFrame(final TCFNodeExecContext parent, final String id, final int frame_no, TCFChildrenRegisters regs) {
super(parent, id);
- this.frame_no = 0;
- this.children_regs = children_regs;
+ this.frame_no = frame_no;
+ if (regs == null) regs = new TCFChildrenRegisters(this);
+ this.children_regs = regs;
+ IChannel channel = model.getLaunch().getChannel();
+ stack_trace_context = new TCFDataCache<IStackTrace.StackTraceContext>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ assert command == null;
+ if (frame_no == 0) {
+ set(null, null, null);
+ return true;
+ }
+ IStackTrace st = model.getLaunch().getService(IStackTrace.class);
+ command = st.getContext(new String[]{ id }, new IStackTrace.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IStackTrace.StackTraceContext[] context) {
+ set(token, error, context[0]);
+ }
+ });
+ return false;
+ }
+ };
+ final Map<BigInteger,TCFSourceRef> line_info_cache = parent.getLineInfoCache();
+ line_info = new TCFDataCache<TCFSourceRef>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ BigInteger n = null;
+ if (frame_no == 0) {
+ if (!parent.validateNode(this)) return false;
+ }
+ else {
+ if (!stack_trace_context.validate()) {
+ stack_trace_context.wait(this);
+ return false;
+ }
+ }
+ String s = getAddress();
+ if (s != null) n = new BigInteger(s);
+ if (n == null) {
+ set(null, null, null);
+ return true;
+ }
+ TCFSourceRef l = line_info_cache.get(n);
+ if (l != null) {
+ set(null, null, l);
+ return true;
+ }
+ ILineNumbers ln = model.getLaunch().getService(ILineNumbers.class);
+ if (ln == null) {
+ l = new TCFSourceRef();
+ l.address = n;
+ set(null, null, l);
+ return true;
+ }
+ final BigInteger n0 = n;
+ final BigInteger n1 = n0.add(BigInteger.valueOf(1));
+ command = ln.mapToSource(parent.id, n0, n1, new ILineNumbers.DoneMapToSource() {
+ public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) {
+ TCFSourceRef l = new TCFSourceRef();
+ l.address = n0;
+ if (error == null && areas != null && areas.length > 0) {
+ for (ILineNumbers.CodeArea area : areas) {
+ if (l.area == null || area.start_line < l.area.start_line) {
+ l.area = area;
+ }
+ }
+ }
+ l.error = error;
+ set(token, null, l);
+ if (error == null) line_info_cache.put(l.address, l);
+ }
+ });
+ return false;
+ }
+ };
}
- TCFNodeStackFrame(TCFNode parent, String id, int frame_no) {
- super(parent, id);
- this.frame_no = frame_no;
- children_regs = new TCFChildrenRegisters(this);
+ TCFNodeStackFrame(TCFNodeExecContext parent, String id, TCFChildrenRegisters children_regs) {
+ this(parent, id, 0, children_regs);
+ }
+
+ TCFNodeStackFrame(TCFNodeExecContext parent, String id, int frame_no) {
+ this(parent, id, frame_no, null);
}
int getFrameNo() {
return frame_no;
}
+
+ void setFrameNo(int frame_no) {
+ assert this.frame_no != 0 && frame_no != 0;
+ this.frame_no = frame_no;
+ }
@Override
void dispose() {
@@ -89,13 +169,15 @@ public class TCFNodeStackFrame extends TCFNode {
public String getAddress() {
assert Protocol.isDispatchThread();
if (frame_no == 0) return parent.getAddress();
- if (stack_trace_context != null) {
- Number addr = stack_trace_context.getReturnAddress();
+ if (!stack_trace_context.isValid()) return null;
+ IStackTrace.StackTraceContext ctx = stack_trace_context.getData();
+ if (ctx != null) {
+ Number addr = ctx.getReturnAddress();
if (addr != null) return addr.toString();
}
return null;
}
-
+
@Override
protected void getData(IChildrenCountUpdate result) {
if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
@@ -139,25 +221,26 @@ public class TCFNodeStackFrame extends TCFNode {
@Override
protected void getData(ILabelUpdate result) {
- result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
- String label = id;
- Number n = null;
- if (frame_no == 0 && parent.getAddress() != null) {
- n = new BigInteger(parent.getAddress());
- }
- else if (stack_trace_context != null) {
- n = stack_trace_context.getReturnAddress();
- }
- if (n == null) {
- label = "...";
+ result.setImageDescriptor(ImageCache.getImageDescriptor(getImageName()), 0);
+ Throwable error = stack_trace_context.getError();
+ if (error == null) error = line_info.getError();
+ if (error != null) {
+ result.setForeground(new RGB(255, 0, 0), 0);
+ result.setLabel(error.getClass().getName() + ": " + error.getMessage(), 0);
}
else {
- label = makeHexAddrString(n);
- if (code_area != null && code_area.file != null) {
- label += ": " + code_area.file + ", line " + (code_area.start_line + 1);
+ TCFSourceRef l = line_info.getData();
+ if (l == null) {
+ result.setLabel("...", 0);
+ }
+ else {
+ String label = makeHexAddrString(l.address);
+ if (l.area != null && l.area.file != null) {
+ label += ": " + l.area.file + ", line " + (l.area.start_line + 1);
+ }
+ result.setLabel(label, 0);
}
}
- result.setLabel(label, 0);
}
private String makeHexAddrString(Number n) {
@@ -174,97 +257,47 @@ public class TCFNodeStackFrame extends TCFNode {
}
void onSourceMappingChange() {
- super.invalidateNode();
- code_address = null;
- code_area = null;
+ line_info.reset();
makeModelDelta(IModelDelta.STATE);
}
void onSuspended() {
- super.invalidateNode();
- stack_trace_context = null;
+ stack_trace_context.reset();
+ line_info.reset();
children_regs.onSuspended();
makeModelDelta(IModelDelta.STATE);
}
+
+ void onRegistersChanged() {
+ children_regs.onRegistersChanged();
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
@Override
public void invalidateNode() {
- super.invalidateNode();
- stack_trace_context = null;
- code_address = null;
- code_area = null;
- children_regs.invalidate();
+ stack_trace_context.reset();
+ line_info.reset();
+ children_regs.reset();
}
@Override
- protected boolean validateNodeData() {
- assert pending_command == null;
- if (node_error != null) return true;
- if (frame_no == 0) {
- if (!children_regs.valid) {
- assert children_regs.node == parent;
- // Need to validate parent for children_regs to be valid.
- ArrayList<TCFNode> nodes = new ArrayList<TCFNode>();
- nodes.add(parent);
- if (!validateNodes(nodes)) return false;
- }
- return validateSourceMapping();
+ public boolean validateNode(Runnable done) {
+ if (frame_no == 0 && !parent.validateNode(done)) return false;
+ stack_trace_context.validate();
+ children_regs.validate();
+ if (!stack_trace_context.isValid()) {
+ stack_trace_context.wait(done);
+ return false;
}
- if (!children_regs.valid && !children_regs.validate()) return false;
- if (stack_trace_context != null) return true;
- IStackTrace st = model.getLaunch().getService(IStackTrace.class);
- pending_command = st.getContext(new String[]{ id }, new IStackTrace.DoneGetContext() {
- public void doneGetContext(IToken token, Exception error, IStackTrace.StackTraceContext[] context) {
- if (pending_command != token) return;
- pending_command = null;
- if (error != null) {
- node_error = error;
- }
- else {
- stack_trace_context = context[0];
- }
- if (!validateSourceMapping()) return;
- validateNode();
- }
- });
- return false;
- }
-
- private boolean validateSourceMapping() {
- BigInteger n = null;
- ILineNumbers ln = model.getLaunch().getService(ILineNumbers.class);
- if (node_error == null && ln != null) {
- String s = getAddress();
- if (s != null) n = new BigInteger(s);
+ if (!children_regs.isValid()) {
+ children_regs.wait(done);
+ return false;
}
- if (n != null && n.equals(code_address)) return true;
- if (n == null) {
- code_area = null;
- code_address = null;
- return true;
+ if (!line_info.validate()) {
+ line_info.wait(done);
+ return false;
}
- final BigInteger n0 = n;
- final BigInteger n1 = n0.add(BigInteger.valueOf(1));
- pending_command = ln.mapToSource(parent.id, n0, n1, new ILineNumbers.DoneMapToSource() {
- public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) {
- if (pending_command != token) return;
- pending_command = null;
- code_area = null;
- if (error != null) {
- node_error = error;
- }
- else if (areas != null && areas.length > 0) {
- for (ILineNumbers.CodeArea area : areas) {
- if (code_area == null || area.start_line < code_area.start_line) {
- code_area = area;
- }
- }
- }
- code_address = n0;
- validateNode();
- }
- });
- return false;
+ return true;
}
@Override
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.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java
new file mode 100644
index 000000000..e8e213406
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSourceRef.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * 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.ui.model;
+
+import java.math.BigInteger;
+
+import org.eclipse.tm.tcf.services.ILineNumbers;
+
+/**
+ * Objects of this class represent a mapping between an address and source code area.
+ */
+class TCFSourceRef {
+ BigInteger address;
+ ILineNumbers.CodeArea area;
+ Throwable error;
+}

Back to the top