diff options
author | eutarass | 2010-02-22 18:19:02 +0000 |
---|---|---|
committer | eutarass | 2010-02-22 18:19:02 +0000 |
commit | 4964b236049b5d07a21c1cf2ce1b20a0c624d567 (patch) | |
tree | af60be954c90030d73c4bf1cb703d064824d11aa /plugins | |
parent | e85adcdb0929eebd3adc3a75795acc850034325f (diff) | |
download | org.eclipse.tcf-4964b236049b5d07a21c1cf2ce1b20a0c624d567.tar.gz org.eclipse.tcf-4964b236049b5d07a21c1cf2ce1b20a0c624d567.tar.xz org.eclipse.tcf-4964b236049b5d07a21c1cf2ce1b20a0c624d567.zip |
Work in progress: more TCF value-add support - all tests have passed when connecting to a target through TCF symbols server value-add.
Diffstat (limited to 'plugins')
29 files changed, 647 insertions, 393 deletions
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/util/TCFDataCache.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/util/TCFDataCache.java index 9b6394973..5ee753e85 100644 --- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/util/TCFDataCache.java +++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/util/TCFDataCache.java @@ -22,6 +22,27 @@ import org.eclipse.tm.tcf.protocol.Protocol; * 1. Valid - cache is in sync with remote data, use getError() and getData() to get cached data; * 2. Invalid - cache is out of sync, start data retrieval by calling validate(); * 3. Pending - cache is waiting result of a command that was sent to remote peer. + * + * A cache instance can be created on any data type that needs to be caches. + * Examples might be context children list, context properties, context state, memory data, + * register data, symbol, variable, etc. + * Clients of cache items can register for cache changes, but don’t need to think about any particular events + * since that is handled by the cache item itself. + * + * A typical cache client should implement Runnable interface. + * The implementation of run() method should: + * + * Validate all cache items required for client task. + * If anything is invalid then client should not alter any shared data structures, + * should discard any intermediate results and register (wait) for changes of invalid cache instance(s) state. + * When cache item state changes, client is invoked again and full validation is restarted. + * Once everything is valid, client completes its task in a single dispatch cycle. + * + * Note: clients should never retain copies of remote data across dispatch cycles! + * Such data would get out of sync and compromise data consistency. + * All remote data and everything derived from remote data should be kept in cache items + * that implement proper event handling and can keep data consistent across dispatch cycles. + * * @param <V> - type of data to be stored in the cache. */ public abstract class TCFDataCache<V> implements Runnable { @@ -29,6 +50,7 @@ public abstract class TCFDataCache<V> implements Runnable { private Throwable error; private boolean valid; private boolean posted; + private boolean disposed; private V data; protected final IChannel channel; @@ -49,7 +71,7 @@ public abstract class TCFDataCache<V> implements Runnable { } /** - * @return true if cache contains up-to-date data (or data retrieval error). + * @return true if cache contains up-to-date data or error. */ public boolean isValid() { return valid; @@ -63,6 +85,13 @@ public abstract class TCFDataCache<V> implements Runnable { } /** + * @return true if cache is disposed. + */ + public boolean isDisposed() { + return disposed; + } + + /** * @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. */ @@ -105,6 +134,7 @@ public abstract class TCFDataCache<V> implements Runnable { */ public void wait(Runnable cb) { assert Protocol.isDispatchThread(); + assert !disposed; assert !valid; if (cb != null) waiting_list.add(cb); } @@ -116,9 +146,9 @@ public abstract class TCFDataCache<V> implements Runnable { public boolean validate() { assert Protocol.isDispatchThread(); if (channel.getState() != IChannel.STATE_OPEN) { - error = null; command = null; valid = true; + error = null; data = null; } else { @@ -159,11 +189,16 @@ public abstract class TCFDataCache<V> implements Runnable { 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; - post(); + if (!disposed) { + if (channel.getState() != IChannel.STATE_OPEN) { + error = null; + data = null; + } + this.error = error; + this.data = data; + valid = true; + post(); + } } /** @@ -176,36 +211,48 @@ public abstract class TCFDataCache<V> implements Runnable { command.cancel(); command = null; } - this.data = data; - error = null; - valid = true; - post(); + if (!disposed) { + this.data = data; + error = null; + valid = true; + post(); + } } /** - * Invalidate the cache. If retrieval is in progress - let it continue. + * Invalidate the cache. + * If retrieval is in progress - let it continue. */ public void reset() { assert Protocol.isDispatchThread(); - error = null; - valid = false; - data = null; - post(); + if (!disposed) { + error = null; + valid = false; + data = null; + post(); + } } /** - * Force cache to invalid state, cancel pending data retrieval if any. + * Invalidate the cache. + * Cancel pending data retrieval if any. */ public void cancel() { - assert Protocol.isDispatchThread(); + reset(); if (command != null) { command.cancel(); command = null; } - error = null; - valid = false; - data = null; - post(); + } + + /** + * Dispose the cache. + * Cancel pending data retrieval if any. + */ + public void dispose() { + cancel(); + valid = true; + disposed = true; } @Override @@ -213,6 +260,7 @@ public abstract class TCFDataCache<V> implements Runnable { StringBuffer bf = new StringBuffer(); bf.append('['); if (valid) bf.append("valid,"); + if (disposed) bf.append("disposed,"); if (posted) bf.append("posted,"); if (error != null) bf.append("error,"); bf.append("data="); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java index c3e18cc16..c38e27406 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java @@ -35,7 +35,9 @@ public class Activator extends AbstractUIPlugin { private static final BundleListener bundle_listener = new BundleListener() { public void bundleChanged(BundleEvent event) { - if (plugin != null && event.getBundle() == plugin.getBundle() && + if (plugin != null && event != null && + plugin.getBundle() != null && + event.getBundle() == plugin.getBundle() && plugin.getBundle().getState() != Bundle.ACTIVE) { Protocol.invokeAndWait(new Runnable() { public void run() { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToArrayCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToArrayCommand.java index 8d8199911..9c2417abf 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToArrayCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToArrayCommand.java @@ -18,6 +18,7 @@ import org.eclipse.tm.internal.tcf.debug.ui.Activator; import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; import org.eclipse.tm.internal.tcf.debug.ui.model.ICastToType; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode; +import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.services.ISymbols; import org.eclipse.tm.tcf.util.TCFDataCache; import org.eclipse.tm.tcf.util.TCFTask; @@ -63,12 +64,16 @@ public class CastToArrayCommand extends AbstractActionDelegate { if (node == null) return; IWorkbenchWindow window = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow(); if (window == null) return; - String base_type_name = getBaseTypeName(); + final String base_type_name = getBaseTypeName(); if (base_type_name == null) return; CastToTypeDialog dialog = new CastToTypeDialog(window.getShell(), node.getModel().getCastToType(node.getID())); if (dialog.open() != Window.OK) return; - String new_type = dialog.getValue().trim(); - node.getModel().setCastToType(node.getID(), base_type_name + "[" + new_type + "]"); + final String new_type = dialog.getValue().trim(); + Protocol.invokeLater(new Runnable() { + public void run() { + node.getModel().setCastToType(node.getID(), base_type_name + "[" + new_type + "]"); + } + }); } private String getBaseTypeName() { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToTypeCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToTypeCommand.java index 34cdc8997..e953ed920 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToTypeCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToTypeCommand.java @@ -18,6 +18,7 @@ import org.eclipse.tm.internal.tcf.debug.ui.Activator; import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; import org.eclipse.tm.internal.tcf.debug.ui.model.ICastToType; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode; +import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.ui.IWorkbenchWindow; public class CastToTypeCommand extends AbstractActionDelegate { @@ -48,14 +49,18 @@ public class CastToTypeCommand extends AbstractActionDelegate { @Override protected void run() { - TCFNode node = getCastToTypeNode(); + final TCFNode node = getCastToTypeNode(); if (node == null) return; IWorkbenchWindow window = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow(); if (window == null) return; CastToTypeDialog dialog = new CastToTypeDialog(window.getShell(), node.getModel().getCastToType(node.getID())); if (dialog.open() != Window.OK) return; - String new_type = dialog.getValue().trim(); - node.getModel().setCastToType(node.getID(), new_type); + final String new_type = dialog.getValue().trim(); + Protocol.invokeLater(new Runnable() { + public void run() { + node.getModel().setCastToType(node.getID(), new_type); + } + }); } @Override diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RestoreDefaultTypeCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RestoreDefaultTypeCommand.java index 1e02cc19b..8bc9bd915 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RestoreDefaultTypeCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RestoreDefaultTypeCommand.java @@ -12,14 +12,19 @@ package org.eclipse.tm.internal.tcf.debug.ui.commands; import org.eclipse.tm.internal.tcf.debug.ui.model.ICastToType; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode; +import org.eclipse.tm.tcf.protocol.Protocol; public class RestoreDefaultTypeCommand extends AbstractActionDelegate { @Override protected void run() { - TCFNode node = getCastToTypeNode(); + final TCFNode node = getCastToTypeNode(); if (node == null) return; - node.getModel().setCastToType(node.getID(), null); + Protocol.invokeLater(new Runnable() { + public void run() { + node.getModel().setCastToType(node.getID(), null); + } + }); } @Override diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SignalsDialog.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SignalsDialog.java index 4a6face7f..4b840b82d 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SignalsDialog.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SignalsDialog.java @@ -246,7 +246,7 @@ class SignalsDialog extends Dialog { new TCFTask<Boolean>() { public void run() { - signal_list.reset(null); + signal_list.dispose(); done(Boolean.TRUE); } }.getE(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFPathMapTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFPathMapTab.java index f2194f6c1..0b37d9bcd 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFPathMapTab.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFPathMapTab.java @@ -11,8 +11,10 @@ package org.eclipse.tm.internal.tcf.debug.ui.launch; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; @@ -219,6 +221,12 @@ public class TCFPathMapTab extends AbstractLaunchConfigurationTab { }); } + List<IPathMap.PathMapRule> getPathMap() { + List<IPathMap.PathMapRule> l = new ArrayList<IPathMap.PathMapRule>(); + for (PathMapRule r : map) l.add(r); + return Collections.unmodifiableList(l); + } + public void initializeFrom(ILaunchConfiguration config) { setErrorMessage(null); setMessage(null); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java index 59886fc00..5f4e4c54d 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java @@ -13,12 +13,14 @@ package org.eclipse.tm.internal.tcf.debug.ui.launch; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.debug.ui.ILaunchConfigurationTab; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; @@ -59,6 +61,7 @@ import org.eclipse.tm.tcf.protocol.IPeer; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener; import org.eclipse.tm.tcf.services.ILocator; +import org.eclipse.tm.tcf.services.IPathMap.PathMapRule; /** @@ -602,7 +605,7 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { } else if (parent == peer_info) { peer_info.locator = Protocol.getLocator(); - createLocatorListener(peer_info); + doneLoadChildren(parent, null, createLocatorListener(peer_info)); } else { final IChannel channel = parent.peer.openChannel(); @@ -615,9 +618,21 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { public void onChannelClosed(final Throwable error) { assert !closed; if (parent.channel != channel) return; - if (parent.children_error == null) { + if (!opened) { doneLoadChildren(parent, error, null); } + else { + if (display != null) { + display.asyncExec(new Runnable() { + public void run() { + if (parent.children_pending) return; + parent.children = null; + parent.children_error = error; + updateItems(parent); + } + }); + } + } closed = true; parent.channel = null; parent.locator = null; @@ -634,7 +649,7 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { parent.channel.close(); } else { - createLocatorListener(parent); + doneLoadChildren(parent, null, createLocatorListener(parent)); } } }); @@ -643,7 +658,7 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { }); } - private void createLocatorListener(PeerInfo peer) { + private PeerInfo[] createLocatorListener(PeerInfo peer) { assert Protocol.isDispatchThread(); Map<String,IPeer> map = peer.locator.getPeers(); PeerInfo[] buf = new PeerInfo[map.size()]; @@ -659,7 +674,7 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { } peer.listener = new LocatorListener(peer); peer.locator.addListener(peer.listener); - doneLoadChildren(peer, null, buf); + return buf; } private void doneLoadChildren(final PeerInfo parent, final Throwable error, final PeerInfo[] children) { @@ -917,7 +932,11 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { Protocol.invokeLater(new Runnable() { public void run() { try { - test[0] = new TCFTestSuite(info.peer, done); + List<PathMapRule> map = null; + for (ILaunchConfigurationTab t : getLaunchConfigurationDialog().getTabs()) { + if (t instanceof TCFPathMapTab) map = ((TCFPathMapTab)t).getPathMap(); + } + test[0] = new TCFTestSuite(info.peer, done, map); } catch (Throwable x) { ArrayList<Throwable> errors = new ArrayList<Throwable>(); 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 6b249c266..b3528c6e6 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 @@ -27,7 +27,6 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { private final int pool_margin; private final Map<String,TCFNode> node_pool = new LinkedHashMap<String,TCFNode>(32, 0.75f, true); - private boolean disposed; private static final TCFNode[] EMPTY_NODE_ARRAY = new TCFNode[0]; @@ -46,15 +45,15 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { /** * Dispose the cache and all nodes in the nodes pool. */ - void dispose() { - assert !disposed; + @Override + public void dispose() { + assert !isDisposed(); if (!node_pool.isEmpty()) { TCFNode a[] = node_pool.values().toArray(new TCFNode[node_pool.size()]); for (int i = 0; i < a.length; i++) a[i].dispose(); assert node_pool.isEmpty(); } - disposed = true; - super.reset(null); + super.dispose(); } /** @@ -71,16 +70,8 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { } } - /** - * Check if the cache is disposed. - * @return true if disposed. - */ - boolean isDisposed() { - return disposed; - } - private void addToPool(Map<String,TCFNode> data) { - assert !disposed; + assert !isDisposed(); for (TCFNode n : data.values()) { assert data.get(n.id) == n; node_pool.put(n.id, n); @@ -105,7 +96,7 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { @Override public void set(IToken token, Throwable error, Map<String,TCFNode> data) { array = null; - if (disposed) { + if (isDisposed()) { // A command can return data after the cache element has been disposed. // Just ignore the data in such case. super.set(token, null, null); @@ -126,7 +117,7 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { */ @Override public void reset(Map<String,TCFNode> data) { - assert !disposed; + assert !isDisposed(); array = null; if (data != null) { super.reset(data); @@ -160,7 +151,7 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { * @param n - a node. */ void add(TCFNode n) { - assert !disposed; + assert !isDisposed(); assert node_pool.get(n.id) == null; node_pool.put(n.id, n); if (isValid()) { 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 f5e00cf92..639a8abc6 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 @@ -90,7 +90,7 @@ public class TCFChildrenExecContext extends TCFChildren { } @Override - protected void dispose() { + public void dispose() { super.dispose(); mem_children.dispose(); run_children.dispose(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java index 67496ab4c..3c86e724a 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java @@ -57,7 +57,7 @@ public class TCFChildrenExpressions extends TCFChildren { } @Override - void dispose() { + public void dispose() { exp_manager.removeExpressionListener(listener); super.dispose(); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java index 3b3768dd5..4b36d9417 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java @@ -40,7 +40,7 @@ public class TCFChildrenSubExpressions extends TCFChildren { } void onCastToTypeChanged() { - reset(); + cancel(); TCFNode a[] = getNodes().toArray(new TCFNode[getNodes().size()]); for (int i = 0; i < a.length; i++) a[i].dispose(); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java index c61901322..24c2c6d34 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java @@ -138,8 +138,8 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { new TCFDebugTask<Boolean>() { public void run() { disposed = true; - expression_value.reset(null); - expression_type.reset(null); + expression_value.dispose(); + expression_type.dispose(); if (remote_expression.isValid() && remote_expression.getData() != null) { final IChannel channel = exec_ctx.getModel().getLaunch().getChannel(); if (channel.getState() == IChannel.STATE_OPEN) { 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 67b7b1930..70755ec66 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 @@ -40,6 +40,7 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru private final Map<TCFNode,TCFNode[]> node2children = new HashMap<TCFNode,TCFNode[]>(); private final Map<TCFNode,ModelDelta> node2delta = new HashMap<TCFNode,ModelDelta>(); + private int all_flags; private TCFNode selection; private boolean posted; private boolean disposed; @@ -157,16 +158,18 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru else { node2flags.put(node, flags); } + all_flags |= flags; post(); } } void setSelection(TCFNode node) { selection = node; - addDelta(node, IModelDelta.REVEAL); + post(); } void post() { + assert Protocol.isDispatchThread(); if (!posted) { Protocol.invokeLater(this); posted = true; @@ -223,7 +226,13 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru if (parent_flags_obj != null) parent_flags = parent_flags_obj; ModelDelta parent = makeDelta(root, node.parent, parent_flags); if (parent == null) return null; - delta = parent.addNode(node, getNodeIndex(node), flags, getNodeChildren(node).length); + int index = -1; + int children = 0; + if ((all_flags & ~(IModelDelta.STATE | IModelDelta.CONTENT)) != 0) { + index = getNodeIndex(node); + children = getNodeChildren(node).length; + } + delta = parent.addNode(node, index, flags, children); } node2delta.put(node, delta); } @@ -235,26 +244,40 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru posted = false; assert Protocol.isDispatchThread(); if (disposed) return; - if (node2flags.isEmpty()) return; + if (node2flags.isEmpty() && selection == null) return; pending_node = null; node2children.clear(); node2delta.clear(); ModelDelta root = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); for (TCFNode node : node2flags.keySet()) makeDelta(root, node, node2flags.get(node)); if (pending_node == null) { + all_flags = 0; node2flags.clear(); if (!node2delta.isEmpty()) { fireModelChanged(root); node2delta.clear(); } if (selection != null) { - root = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); - makeDelta(root, selection, IModelDelta.SELECT); - fireModelChanged(root); + all_flags = IModelDelta.REVEAL; + ModelDelta root1 = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); + makeDelta(root1, selection, IModelDelta.REVEAL); + node2delta.clear(); + all_flags = IModelDelta.SELECT; + ModelDelta root2 = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); + makeDelta(root2, selection, IModelDelta.SELECT); node2delta.clear(); - selection = null; + if (pending_node == null) { + fireModelChanged(root1); + fireModelChanged(root2); + selection = null; + } + all_flags = 0; } } + + if (pending_node == null) { + // OK + } else if (pending_node.getData(children_count_update, this)) { assert false; post(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeArrayPartition.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeArrayPartition.java index adaf843ce..07e98d1dc 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeArrayPartition.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeArrayPartition.java @@ -33,7 +33,6 @@ public class TCFNodeArrayPartition extends TCFNode { @Override void dispose() { - children.reset(null); children.dispose(); super.dispose(); } 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 df5cb65e2..5b5fc27cd 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 @@ -45,7 +45,7 @@ public class TCFNodeExecContext extends TCFNode { private final TCFDataCache<IRunControl.RunControlContext> run_context; private final TCFDataCache<IProcesses.ProcessContext> prs_context; private final TCFDataCache<TCFContextState> state; - private final TCFDataCache<BigInteger> address; + private final TCFDataCache<BigInteger> address; // Current PC as BigInteger private final Map<BigInteger,TCFSourceRef> line_info_cache; @@ -166,11 +166,11 @@ public class TCFNodeExecContext extends TCFNode { @Override void dispose() { - run_context.reset(null); - prs_context.reset(null); - mem_context.reset(null); - state.reset(null); - address.reset(null); + run_context.dispose(); + prs_context.dispose(); + mem_context.dispose(); + state.dispose(); + address.dispose(); children_exec.dispose(); children_stack.dispose(); super.dispose(); @@ -359,6 +359,8 @@ public class TCFNodeExecContext extends TCFNode { void onContextChanged(IRunControl.RunControlContext context) { assert !disposed; run_context.reset(context); + state.reset(); + children_stack.reset(); children_stack.onSourceMappingChange(); addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); } @@ -466,8 +468,8 @@ public class TCFNodeExecContext extends TCFNode { addModelDelta(IModelDelta.CONTENT); } - // Return true if at least one child is suspended - // The method will fail if node is not validated, see validateChildrenState() + // Return true if at least one child is suspended. + // Return null if waiting for a cache element. private Boolean hasSuspendedChildren(Runnable done) { if (!children_exec.validate(done)) return null; Map<String,TCFNode> m = children_exec.getData(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java index d63cf0bb7..c83970c23 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java @@ -210,12 +210,22 @@ public class TCFNodeExpression extends TCFNode implements IElementEditor, ICastT e = new Expression(context); e.must_be_disposed = true; } - set(token, error, e); - if (isDisposed()) disposeExpression(); + if (!isDisposed()) set(token, error, e); + else if (e != null) e.dispose(); } }); return false; } + @Override + public void cancel() { + if (isValid() && getData() != null) getData().dispose(); + super.cancel(); + } + @Override + public void dispose() { + if (isValid() && getData() != null) getData().dispose(); + super.dispose(); + } }; value = new TCFDataCache<IExpressions.Value>(channel) { @Override @@ -380,108 +390,95 @@ public class TCFNodeExpression extends TCFNode implements IElementEditor, ICastT } }; type_name = new TCFDataCache<String>(channel) { - String name; - TCFDataCache<ISymbols.Symbol> type_cache; @Override protected boolean startDataRetrieval() { - if (name == null) type_cache = type; - if (!type_cache.validate(this)) return false; - String s = null; - boolean get_base_type = false; - ISymbols.Symbol t = type_cache.getData(); - if (t != null) { - s = t.getName(); - if (s != null && t.getTypeClass() == ISymbols.TypeClass.composite) { - s = "struct " + s; - } - if (s == null && t.getSize() == 0) s = "void"; - if (s == null) { - switch (t.getTypeClass()) { - case integer: - switch (t.getSize()) { - case 1: s = "char"; break; - case 2: s = "short"; break; - case 4: s = "int"; break; - case 8: s = "long long"; break; - default: s = "<Integer>"; break; - } - break; - case cardinal: - switch (t.getSize()) { - case 1: s = "unsigned char"; break; - case 2: s = "unsigned short"; break; - case 4: s = "unsigned"; break; - case 8: s = "unsigned long long"; break; - default: s = "<Unsigned>"; break; - } - break; - case real: - switch (t.getSize()) { - case 4: s = "float"; break; - case 8: s = "double"; break; - default: s = "<Float>"; break; + String name = null; + TCFDataCache<ISymbols.Symbol> type_cache = type; + for (;;) { + String s = null; + boolean get_base_type = false; + if (!type_cache.validate(this)) return false; + ISymbols.Symbol type_symbol = type_cache.getData(); + if (type_symbol != null) { + s = type_symbol.getName(); + if (s != null && type_symbol.getTypeClass() == ISymbols.TypeClass.composite) s = "struct " + s; + if (s == null && type_symbol.getSize() == 0) s = "void"; + if (s == null) { + switch (type_symbol.getTypeClass()) { + case integer: + switch (type_symbol.getSize()) { + case 1: s = "char"; break; + case 2: s = "short"; break; + case 4: s = "int"; break; + case 8: s = "long long"; break; + default: s = "<Integer>"; break; + } + break; + case cardinal: + switch (type_symbol.getSize()) { + case 1: s = "unsigned char"; break; + case 2: s = "unsigned short"; break; + case 4: s = "unsigned"; break; + case 8: s = "unsigned long long"; break; + default: s = "<Unsigned>"; break; + } + break; + case real: + switch (type_symbol.getSize()) { + case 4: s = "float"; break; + case 8: s = "double"; break; + default: s = "<Float>"; break; + } + break; + case pointer: + s = "*"; + get_base_type = true; + break; + case array: + s = "[]"; + get_base_type = true; + break; + case composite: + s = "<Structure>"; + break; + case function: + s = "<Function>"; + break; } - break; - case pointer: - s = "*"; - get_base_type = true; - break; - case array: - s = "[]"; - get_base_type = true; - break; - case composite: - s = "<Structure>"; - break; - case function: - s = "<Function>"; - break; } } - } - if (s == null) name = "N/A"; - else if (name == null) name = s; - else if (!get_base_type) name = s + " " + name; - else name = s + name; - if (get_base_type) { - type_cache = model.getSymbolInfoCache(t.getBaseTypeID()); - if (type_cache == null) { + if (s == null) { name = "N/A"; + break; } - else { - Protocol.invokeLater(this); - return false; + if (name == null) name = s; + else if (!get_base_type) name = s + " " + name; + else name = s + name; + + if (!get_base_type) break; + + type_cache = model.getSymbolInfoCache(type_symbol.getBaseTypeID()); + if (type_cache == null) { + name = "N/A"; + break; } } set(null, null, name); return true; } - @Override - public void reset() { - super.reset(); - name = null; - } }; children = new TCFChildrenSubExpressions(this, 0, 0, 0); } - private void disposeExpression() { - if (expression.isValid() && expression.getData() != null) { - expression.getData().dispose(); - } - expression.cancel(); - } - @Override void dispose() { - var_expression.reset(null); - value.reset(null); - type.reset(null); - type_name.reset(null); - string.reset(null); - children.reset(null); + var_expression.dispose(); + value.dispose(); + type.dispose(); + type_name.dispose(); + string.dispose(); children.dispose(); - disposeExpression(); + expression.dispose(); super.dispose(); } @@ -506,11 +503,11 @@ public class TCFNodeExpression extends TCFNode implements IElementEditor, ICastT public void onCastToTypeChanged() { - disposeExpression(); - value.reset(); - type.reset(); - type_name.reset(); - string.reset(); + expression.cancel(); + value.cancel(); + type.cancel(); + type_name.cancel(); + string.cancel(); children.onCastToTypeChanged(); addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); } 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 4f4ab22f6..9413e9934 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 @@ -82,8 +82,8 @@ public class TCFNodeRegister extends TCFNode implements IElementEditor { @Override public void dispose() { - context.reset(null); - value.reset(null); + context.dispose(); + value.dispose(); super.dispose(); } 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 9c685522b..6d219f875 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 @@ -176,15 +176,11 @@ public class TCFNodeStackFrame extends TCFNode { this.frame_no = frame_no; } - public TCFDataCache<TCFSourceRef> getLineInfo() { - return line_info; - } - @Override void dispose() { - stack_trace_context.reset(null); - line_info.reset(null); - address.reset(null); + stack_trace_context.dispose(); + line_info.dispose(); + address.dispose(); children_regs.dispose(); children_vars.dispose(); children_exps.dispose(); @@ -198,6 +194,10 @@ public class TCFNodeStackFrame extends TCFNode { children_exps.dispose(id); } + public TCFDataCache<TCFSourceRef> getLineInfo() { + return line_info; + } + public TCFDataCache<IStackTrace.StackTraceContext> getStackTraceContext() { return stack_trace_context; } @@ -224,19 +224,33 @@ public class TCFNodeStackFrame extends TCFNode { return super.getRelevantModelDeltaFlags(p); } + private TCFChildren getChildren(IPresentationContext ctx) { + String id = ctx.getId(); + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(id)) return children_regs; + if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(id)) return children_vars; + if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(id)) return children_exps; + return null; + } + @Override - protected boolean getData(IChildrenCountUpdate result, Runnable done) { - if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_regs.validate(done)) return false; - result.setChildCount(children_regs.size()); + protected boolean getData(IHasChildrenUpdate result, Runnable done) { + TCFChildren c = getChildren(result.getPresentationContext()); + if (c != null) { + if (!c.validate(done)) return false; + result.setHasChilren(c.size() > 0); } - else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_vars.validate(done)) return false; - result.setChildCount(children_vars.size()); + else { + result.setHasChilren(false); } - else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_exps.validate(done)) return false; - result.setChildCount(children_exps.size()); + return true; + } + + @Override + protected boolean getData(IChildrenCountUpdate result, Runnable done) { + TCFChildren c = getChildren(result.getPresentationContext()); + if (c != null) { + if (!c.validate(done)) return false; + result.setChildCount(c.size()); } else { result.setChildCount(0); @@ -247,20 +261,13 @@ public class TCFNodeStackFrame extends TCFNode { @Override protected boolean getData(IChildrenUpdate result, Runnable done) { TCFNode[] arr = null; - if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_regs.validate(done)) return false; - arr = children_regs.toArray(); - } - else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_vars.validate(done)) return false; - arr = children_vars.toArray(); - } - else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_exps.validate(done)) return false; - arr = children_exps.toArray(); + TCFChildren c = getChildren(result.getPresentationContext()); + if (c != null) { + if (!c.validate(done)) return false; + arr = c.toArray(); } else { - arr = new TCFNode[0]; + return true; } int offset = 0; int r_offset = result.getOffset(); @@ -275,28 +282,7 @@ public class TCFNodeStackFrame extends TCFNode { } @Override - protected boolean getData(IHasChildrenUpdate result, Runnable done) { - if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_regs.validate(done)) return false; - result.setHasChilren(children_regs.size() > 0); - } - else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_vars.validate(done)) return false; - result.setHasChilren(children_vars.size() > 0); - } - else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_exps.validate(done)) return false; - result.setHasChilren(children_exps.size() > 0); - } - else { - result.setHasChilren(false); - } - return true; - } - - @Override protected boolean getData(ILabelUpdate result, Runnable done) { - String image_name = null; TCFChildrenStackTrace stack_trace_cache = ((TCFNodeExecContext)parent).getStackTrace(); if (!stack_trace_cache.validate(done)) return false; if (stack_trace_cache.getData().get(id) == null) { @@ -304,14 +290,21 @@ public class TCFNodeStackFrame extends TCFNode { } else { TCFDataCache<TCFContextState> state_cache = ((TCFNodeExecContext)parent).getState(); - if (!state_cache.validate(done)) return false; - TCFContextState state_data = state_cache.getData(); - if (state_data != null && state_data.is_suspended) image_name = ImageCache.IMG_STACK_FRAME_SUSPENDED; - else image_name = ImageCache.IMG_STACK_FRAME_RUNNING; - if (!stack_trace_context.validate(done)) return false; - if (!line_info.validate(done)) return false; - Throwable error = stack_trace_context.getError(); + TCFDataCache<?> pending = null; + if (!state_cache.validate()) pending = state_cache; + if (!stack_trace_context.validate()) pending = stack_trace_context; + if (!line_info.validate()) pending = line_info; + if (pending != null) { + pending.wait(done); + return false; + } + Throwable error = state_cache.getError(); + if (error == null) error = stack_trace_context.getError(); if (error == null) error = line_info.getError(); + TCFContextState state_data = state_cache.getData(); + String image_name = state_data != null && state_data.is_suspended ? + ImageCache.IMG_STACK_FRAME_SUSPENDED : + ImageCache.IMG_STACK_FRAME_RUNNING; if (error != null && state_data != null && state_data.is_suspended) { result.setForeground(new RGB(255, 0, 0), 0); result.setLabel(error.getClass().getName() + ": " + error.getMessage(), 0); @@ -329,8 +322,8 @@ public class TCFNodeStackFrame extends TCFNode { result.setLabel(label, 0); } } + result.setImageDescriptor(ImageCache.getImageDescriptor(image_name), 0); } - result.setImageDescriptor(ImageCache.getImageDescriptor(image_name), 0); return true; } @@ -352,9 +345,9 @@ public class TCFNodeStackFrame extends TCFNode { } void onSuspended() { - stack_trace_context.reset(); - line_info.reset(); - address.reset(); + stack_trace_context.cancel(); + line_info.cancel(); + address.cancel(); children_regs.onSuspended(); children_vars.onSuspended(); children_exps.onSuspended(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/trace/TraceView.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/trace/TraceView.java index 58c4d7479..48fefb008 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/trace/TraceView.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/trace/TraceView.java @@ -11,18 +11,24 @@ package org.eclipse.tm.internal.tcf.debug.ui.trace; import java.io.UnsupportedEncodingException; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Text; import org.eclipse.tm.tcf.core.AbstractChannel; import org.eclipse.tm.tcf.protocol.IChannel; import org.eclipse.tm.tcf.protocol.IPeer; +import org.eclipse.tm.tcf.protocol.JSON; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.ui.part.ViewPart; @@ -93,10 +99,17 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener Page(AbstractChannel channel) { this.channel = channel; + update_thread.setName("TCF Trace View"); update_thread.start(); } public void dispose() { + if (closed) return; + Protocol.invokeAndWait(new Runnable() { + public void run() { + channel.removeTraceListener(Page.this); + } + }); synchronized (this) { closed = true; update_thread.interrupt(); @@ -116,7 +129,6 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener public synchronized void onChannelClosed(Throwable error) { if (error == null) { - channel.removeTraceListener(this); getSite().getShell().getDisplay().asyncExec(new Runnable() { public void run() { dispose(); @@ -148,15 +160,7 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener bf.append(name); } if (data != null) { - int i = 0; - while (i < data.length) { - int j = i; - while (j < data.length && data[j] != 0) j++; - bf.append(' '); - bf.append(new String(data, i, j - i, "UTF8")); - if (j < data.length && data[j] == 0) j++; - i = j; - } + appendData(bf, data); } bf.append('\n'); bf_line_cnt++; @@ -185,15 +189,7 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener bf.append(name); } if (data != null) { - int i = 0; - while (i < data.length) { - int j = i; - while (j < data.length && data[j] != 0) j++; - bf.append(' '); - bf.append(new String(data, i, j - i, "UTF8")); - if (j < data.length && data[j] == 0) j++; - i = j; - } + appendData(bf, data); } bf.append('\n'); bf_line_cnt++; @@ -228,7 +224,6 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener Protocol.invokeAndWait(new Runnable() { public void run() { Protocol.removeChannelOpenListener(TraceView.this); - for (Page p : pages) p.channel.removeTraceListener(p); } }); for (Page p : pages) p.dispose(); @@ -274,6 +269,81 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener }); } + private void appendData(StringBuffer bf, byte[] data) throws UnsupportedEncodingException { + int pos = bf.length(); + try { + Object[] o = JSON.parseSequence(data); + for (int i = 0; i < o.length; i++) { + bf.append(' '); + appendJSON(bf, o[i]); + } + } + catch (Throwable z) { + bf.setLength(pos); + for (int i = 0; i < data.length; i++) { + bf.append(' '); + int x = (data[i] >> 4) & 0xf; + int y = data[i] & 0xf; + bf.append((char)(x < 10 ? '0' + x : 'a' + x - 10)); + bf.append((char)(y < 10 ? '0' + y : 'a' + y - 10)); + } + } + } + + private void appendJSON(StringBuffer bf, Object o) { + if (o instanceof byte[]) { + int l = ((byte[])o).length; + bf.append('('); + bf.append(l); + bf.append(')'); + } + else if (o instanceof Collection) { + int cnt = 0; + bf.append('['); + for (Object i : (Collection<?>)o) { + if (cnt > 0) bf.append(','); + appendJSON(bf, i); + cnt++; + } + bf.append(']'); + } + else if (o instanceof Map) { + int cnt = 0; + bf.append('{'); + for (Object k : ((Map<?,?>)o).keySet()) { + if (cnt > 0) bf.append(','); + bf.append(k.toString()); + bf.append(':'); + appendJSON(bf, ((Map<?,?>)o).get(k)); + cnt++; + } + bf.append('}'); + } + else if (o instanceof String) { + bf.append('"'); + String s = (String)o; + int l = s.length(); + for (int i = 0; i < l; i++) { + char ch = s.charAt(i); + if (ch < ' ') { + bf.append('\\'); + bf.append('u'); + for (int j = 0; j < 4; j++) { + int x = (ch >> (4 * (3 - j))) & 0xf; + bf.append((char)(x < 10 ? '0' + x : 'a' + x - 10)); + } + } + else { + bf.append(ch); + } + } + bf.append('"'); + } + else { + bf.append(o); + } + } + private void showTabs() { boolean b = false; if (no_data != null) { @@ -283,6 +353,38 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener } if (tabs == null) { tabs = new TabFolder(parent, SWT.NONE); + Menu menu = new Menu(tabs); + MenuItem mi_close = new MenuItem(menu, SWT.NONE); + mi_close.setText("Close"); + mi_close.addSelectionListener(new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + } + public void widgetSelected(SelectionEvent e) { + if (tabs == null) return; + TabItem[] s = tabs.getSelection(); + for (TabItem i : s) { + Page p = tab2page.get(i); + if (p != null) p.dispose(); + else i.dispose(); + } + } + }); + MenuItem mi_close_all = new MenuItem(menu, SWT.NONE); + mi_close_all.setText("Close All"); + mi_close_all.addSelectionListener(new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + } + public void widgetSelected(SelectionEvent e) { + if (tabs == null) return; + TabItem[] s = tabs.getItems(); + for (TabItem i : s) { + Page p = tab2page.get(i); + if (p != null) p.dispose(); + else i.dispose(); + } + } + }); + tabs.setMenu(menu); b = true; } if (b) parent.layout(); diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java index 6ee7d861a..abfd4f531 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java @@ -530,8 +530,8 @@ public class TCFLaunch extends Launch { listeners.remove(listener); } + /** Thread safe method */ public IChannel getChannel() { - assert Protocol.isDispatchThread(); return channel; } diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/Main.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/Main.java index 8724c35ca..9b9d80dfc 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/Main.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/Main.java @@ -110,7 +110,7 @@ public class Main { } private static void runTestSuite(IPeer peer) { - TCFTestSuite.TestListener listenr = new TCFTestSuite.TestListener() { + TCFTestSuite.TestListener listener = new TCFTestSuite.TestListener() { public void done(Collection<Throwable> errors) { if (errors == null || errors.isEmpty()) { @@ -129,7 +129,7 @@ public class Main { }; try { - new TCFTestSuite(peer, listenr); + new TCFTestSuite(peer, listener, null); } catch (Throwable x) { System.err.println("Cannot start test suite:"); diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TCFTestSuite.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TCFTestSuite.java index 6c9c6cc63..21fb3b639 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TCFTestSuite.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TCFTestSuite.java @@ -16,11 +16,13 @@ import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.Map; import org.eclipse.tm.tcf.protocol.IChannel; import org.eclipse.tm.tcf.protocol.IPeer; import org.eclipse.tm.tcf.protocol.Protocol; +import org.eclipse.tm.tcf.services.IPathMap.PathMapRule; /** * TCF Test Suite implements stress testing of communication channels and capabilities of remote peer. @@ -49,7 +51,7 @@ public class TCFTestSuite { public void done(Collection<Throwable> errors); } - public TCFTestSuite(final IPeer peer, final TestListener listener) throws IOException { + public TCFTestSuite(final IPeer peer, final TestListener listener, final List<PathMapRule> path_map) throws IOException { this.listener = listener; pending_tests.add(new Runnable() { public void run() { @@ -77,6 +79,14 @@ public class TCFTestSuite { }); pending_tests.add(new Runnable() { public void run() { + listener.progress("Running Path Map Test...", ++count_done, count_total); + for (IChannel channel : channels) { + active_tests.put(new TestPathMap(TCFTestSuite.this, channel, path_map), channel); + } + } + }); + pending_tests.add(new Runnable() { + public void run() { listener.progress("Running Expressions Test...", ++count_done, count_total); for (IChannel channel : channels) { active_tests.put(new TestExpressions(TCFTestSuite.this, channel), channel); @@ -119,14 +129,6 @@ public class TCFTestSuite { }); pending_tests.add(new Runnable() { public void run() { - listener.progress("Running Path Map Test...", ++count_done, count_total); - for (IChannel channel : channels) { - active_tests.put(new TestPathMap(TCFTestSuite.this, channel), channel); - } - } - }); - pending_tests.add(new Runnable() { - public void run() { listener.progress("Running Interability Test...", ++count_done, count_total); for (int i = 0; i < channels.length; i++) { ITCFTest test = null; diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestAttachTerminate.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestAttachTerminate.java index 35ea71bba..a2211c774 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestAttachTerminate.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestAttachTerminate.java @@ -15,6 +15,7 @@ import java.util.HashSet; import java.util.Map; import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IErrorReport; import org.eclipse.tm.tcf.protocol.IToken; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.services.IDiagnostics; @@ -27,13 +28,12 @@ class TestAttachTerminate implements ITCFTest, IRunControl.RunControlListener { private final IDiagnostics diag; private final IRunControl rc; - private final HashMap<String,IRunControl.RunControlContext> map = + private int cnt = 0; + + private final HashMap<String,IRunControl.RunControlContext> ctx_map = new HashMap<String,IRunControl.RunControlContext>(); private final HashSet<String> process_ids = new HashSet<String>(); - private int cnt; - private int wait_cnt; - TestAttachTerminate(TCFTestSuite test_suite, IChannel channel) { this.test_suite = test_suite; diag = channel.getRemoteService(IDiagnostics.class); @@ -41,11 +41,11 @@ class TestAttachTerminate implements ITCFTest, IRunControl.RunControlListener { } public void start() { - if (diag == null) { + if (diag == null || rc == null) { test_suite.done(this, null); } else { - if (rc != null) rc.addListener(this); + rc.addListener(this); diag.getTestList(new IDiagnostics.DoneGetTestList() { public void doneGetTestList(IToken token, Throwable error, String[] list) { assert test_suite.isActive(TestAttachTerminate.this); @@ -56,6 +56,25 @@ class TestAttachTerminate implements ITCFTest, IRunControl.RunControlListener { for (int i = 0; i < list.length; i++) { if (list[i].equals("RCBP1")) { startProcess(); + Protocol.invokeLater(1000, new Runnable() { + int cnt = 0; + public void run() { + if (!test_suite.isActive(TestAttachTerminate.this)) return; + cnt++; + if (cnt < 10) { + Protocol.invokeLater(1000, this); + } + else if (test_suite.cancel) { + exit(null); + } + else if (process_ids.isEmpty()) { + exit(new Error("Missing 'contextAdded' event")); + } + else { + exit(new Error("Missing 'contextRemoved' event for " + process_ids)); + } + } + }); return; } } @@ -67,70 +86,34 @@ class TestAttachTerminate implements ITCFTest, IRunControl.RunControlListener { } private void startProcess() { - if (test_suite.cancel || cnt == 4) { - if (!process_ids.isEmpty()) { - new Thread() { - public void run() { - try { - sleep(100); - Protocol.invokeLater(new Runnable() { - public void run() { - wait_cnt++; - if (test_suite.cancel) exit(null); - if (process_ids.isEmpty()) { - exit(null); - } - else if (wait_cnt < 300) { - startProcess(); - } - else { - exit(new Error("Missing 'contextRemoved' event for " + process_ids)); - } - } - }); - } - catch (IllegalStateException x) { - } - catch (InterruptedException x) { - } - } - }.start(); - } - else { - exit(null); - } - return; - } - cnt++; - diag.runTest("RCBP1", new IDiagnostics.DoneRunTest() { - public void doneRunTest(IToken token, Throwable error, String context_id) { - if (error != null) { - exit(error); - } - else { - assert context_id != null; - if (rc != null && map.get(context_id) == null) { - exit(new Error("Missing 'contextAdded' event for context " + context_id)); + for (int i = 0; i < 4; i++) { + diag.runTest("RCBP1", new IDiagnostics.DoneRunTest() { + public void doneRunTest(IToken token, Throwable error, String context_id) { + cnt--; + if (error != null) { + exit(error); } - process_ids.add(context_id); - diag.cancelTest(context_id, new IDiagnostics.DoneCancelTest() { - public void doneCancelTest(IToken token, Throwable error) { - if (error != null) { - exit(error); - } - else { - startProcess(); - } + else { + assert context_id != null; + if (ctx_map.get(context_id) == null) { + exit(new Error("Missing 'contextAdded' event for context " + context_id)); } - }); + process_ids.add(context_id); + diag.cancelTest(context_id, new IDiagnostics.DoneCancelTest() { + public void doneCancelTest(IToken token, Throwable error) { + if (error != null) exit(error); + } + }); + } } - } - }); + }); + cnt++; + } } private void exit(Throwable x) { if (!test_suite.isActive(this)) return; - if (rc != null) rc.removeListener(this); + rc.removeListener(this); test_suite.done(this, x); } @@ -148,23 +131,23 @@ class TestAttachTerminate implements ITCFTest, IRunControl.RunControlListener { public void contextAdded(RunControlContext[] contexts) { for (RunControlContext ctx : contexts) { - if (map.get(ctx.getID()) != null) exit(new Error("Invalid 'contextAdded' event")); - map.put(ctx.getID(), ctx); + if (ctx_map.get(ctx.getID()) != null) exit(new Error("Invalid 'contextAdded' event")); + ctx_map.put(ctx.getID(), ctx); } } public void contextChanged(RunControlContext[] contexts) { for (RunControlContext ctx : contexts) { - if (map.get(ctx.getID()) == null) return; - map.put(ctx.getID(), ctx); + if (ctx_map.get(ctx.getID()) == null) return; + ctx_map.put(ctx.getID(), ctx); } } public void contextException(String context, String msg) { - IRunControl.RunControlContext ctx = map.get(context); + IRunControl.RunControlContext ctx = ctx_map.get(context); if (ctx == null) return; if (process_ids.contains(ctx.getParentID())) { - /* TODO: FIXME: Linux-64 PTrace sometimes intercepts SIGKILL instead of delivering it to the process + /* exit(new Error("Unexpected 'contextException' event for " + context + ": " + msg)); */ } @@ -172,22 +155,27 @@ class TestAttachTerminate implements ITCFTest, IRunControl.RunControlListener { public void contextRemoved(String[] context_ids) { for (String id : context_ids) { - map.remove(id); + ctx_map.remove(id); process_ids.remove(id); } + if (cnt == 0 && process_ids.isEmpty()) exit(null); } public void contextResumed(String context) { } - public void contextSuspended(String context, String pc, String reason, - Map<String, Object> params) { + public void contextSuspended(String context, String pc, String reason, Map<String,Object> params) { assert context != null; - IRunControl.RunControlContext ctx = map.get(context); - if (ctx == null) return; - if (process_ids.contains(ctx.getParentID())) { + IRunControl.RunControlContext ctx = ctx_map.get(context); + if (ctx != null && process_ids.contains(ctx.getParentID())) { ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() { public void doneCommand(IToken token, Exception error) { + if (error instanceof IErrorReport) { + int code = ((IErrorReport)error).getErrorCode(); + if (code == IErrorReport.TCF_ERROR_ALREADY_RUNNING) return; + if (code == IErrorReport.TCF_ERROR_INV_CONTEXT) return; + } + if (error != null) exit(error); } }); } diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestExpressions.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestExpressions.java index d36f51caf..9975b5773 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestExpressions.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestExpressions.java @@ -16,13 +16,16 @@ import java.util.HashMap; import java.util.Map; import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IErrorReport; import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.services.IBreakpoints; import org.eclipse.tm.tcf.services.IDiagnostics; import org.eclipse.tm.tcf.services.IExpressions; import org.eclipse.tm.tcf.services.IRunControl; import org.eclipse.tm.tcf.services.IStackTrace; import org.eclipse.tm.tcf.services.ISymbols; +import org.eclipse.tm.tcf.services.IRunControl.RunControlContext; class TestExpressions implements ITCFTest, IRunControl.RunControlListener, IExpressions.ExpressionsListener, IBreakpoints.BreakpointsListener { @@ -40,13 +43,13 @@ class TestExpressions implements ITCFTest, private IDiagnostics.ISymbol sym_func3; private String process_id; private String thread_id; - private boolean process_exited; private boolean test_done; private IRunControl.RunControlContext thread_ctx; private String suspended_pc; private boolean waiting_suspend; private String[] stack_trace; private String[] local_vars; + private final HashMap<String,IRunControl.RunControlContext> ctx_map = new HashMap<String,IRunControl.RunControlContext>(); private final Map<String,IExpressions.Expression> expr_ctx = new HashMap<String,IExpressions.Expression>(); private final Map<String,IExpressions.Value> expr_val = new HashMap<String,IExpressions.Value>(); private final Map<String,ISymbols.Symbol> expr_sym = new HashMap<String,ISymbols.Symbol>(); @@ -85,6 +88,7 @@ class TestExpressions implements ITCFTest, "(func2_local2 >> 1) == 1", "+func2_local2 == 2", "-func2_local2 == -2", + "(short)(int)(long)((char *)func2_local2 + 1) == 3", "((func2_local1 + func2_local2) * 2 - 2) / 2 == 2", "func2_local3.f_struct->f_struct->f_struct == &func2_local3" }; @@ -117,6 +121,22 @@ class TestExpressions implements ITCFTest, for (int i = 0; i < list.length; i++) { if (list[i].equals("RCBP1")) { runTest(); + Protocol.invokeLater(1000, new Runnable() { + int cnt = 0; + public void run() { + if (!test_suite.isActive(TestExpressions.this)) return; + cnt++; + if (cnt < 10) { + Protocol.invokeLater(1000, this); + } + else if (test_suite.cancel) { + exit(null); + } + else { + exit(new Error("Missing 'contextRemoved' event for " + process_id)); + } + } + }); return; } } @@ -407,7 +427,7 @@ class TestExpressions implements ITCFTest, test_done = true; diag.cancelTest(process_id, new IDiagnostics.DoneCancelTest() { public void doneCancelTest(IToken token, Throwable error) { - exit(error); + if (error != null) exit(error); } }); } @@ -434,9 +454,17 @@ class TestExpressions implements ITCFTest, } public void contextAdded(IRunControl.RunControlContext[] contexts) { + for (RunControlContext ctx : contexts) { + if (ctx_map.get(ctx.getID()) != null) exit(new Error("Invalid 'contextAdded' event")); + ctx_map.put(ctx.getID(), ctx); + } } public void contextChanged(IRunControl.RunControlContext[] contexts) { + for (RunControlContext ctx : contexts) { + if (ctx_map.get(ctx.getID()) == null) return; + ctx_map.put(ctx.getID(), ctx); + } } public void contextException(String context, String msg) { @@ -444,9 +472,11 @@ class TestExpressions implements ITCFTest, public void contextRemoved(String[] context_ids) { for (String id : context_ids) { + ctx_map.remove(id); if (id.equals(process_id)) { - process_exited = true; - if (!test_done) exit(new Exception("Test process exited too soon")); + if (test_done) exit(null); + else exit(new Exception("Test process exited too soon")); + return; } } } @@ -462,6 +492,21 @@ class TestExpressions implements ITCFTest, runTest(); } } + if (test_done) { + IRunControl.RunControlContext ctx = ctx_map.get(context); + if (ctx != null && process_id != null && process_id.equals(ctx.getParentID())) { + ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error instanceof IErrorReport) { + int code = ((IErrorReport)error).getErrorCode(); + if (code == IErrorReport.TCF_ERROR_ALREADY_RUNNING) return; + if (code == IErrorReport.TCF_ERROR_INV_CONTEXT) return; + } + if (error != null) exit(error); + } + }); + } + } } //--------------------------- Expressions listener ---------------------------// @@ -473,7 +518,7 @@ class TestExpressions implements ITCFTest, @SuppressWarnings("unchecked") public void breakpointStatusChanged(String id, Map<String,Object> status) { - if (id.equals(bp_id) && process_id != null && !process_exited) { + if (id.equals(bp_id) && process_id != null) { String s = (String)status.get(IBreakpoints.STATUS_ERROR); if (s != null) exit(new Exception("Invalid BP status: " + s)); Collection<Map<String,Object>> list = (Collection<Map<String,Object>>)status.get(IBreakpoints.STATUS_INSTANCES); diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestPathMap.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestPathMap.java index 1b75e020f..998f07a02 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestPathMap.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestPathMap.java @@ -1,6 +1,7 @@ package org.eclipse.tm.internal.tcf.debug.tests; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; @@ -12,6 +13,7 @@ import org.eclipse.tm.tcf.services.IPathMap.PathMapRule; class TestPathMap implements ITCFTest { private final TCFTestSuite test_suite; + private final List<PathMapRule> map; private final IPathMap service; private final Random rnd = new Random(); @@ -62,8 +64,9 @@ class TestPathMap implements ITCFTest { } } - TestPathMap(TCFTestSuite test_suite, IChannel channel) { + TestPathMap(TCFTestSuite test_suite, IChannel channel, List<PathMapRule> map) { this.test_suite = test_suite; + this.map = map; service = channel.getRemoteService(IPathMap.class); } @@ -78,7 +81,16 @@ class TestPathMap implements ITCFTest { private void test_map() { if (cnt >= 40) { - exit(null); + if (map == null) { + exit(null); + } + else { + service.set(map.toArray(new PathMapRule[map.size()]), new IPathMap.DoneSet() { + public void doneSet(IToken token, Exception error) { + exit(error); + } + }); + } } else { cnt++; diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestRCBP1.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestRCBP1.java index b86b20d55..b47a39155 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestRCBP1.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/tests/TestRCBP1.java @@ -78,7 +78,6 @@ class TestRCBP1 implements ITCFTest, final String pc; final String reason; final Map<String,Object> params; - boolean resumed; SuspendedContext(String id, String pc, String reason, Map<String,Object> params) { this.id = id; @@ -338,7 +337,7 @@ class TestRCBP1 implements ITCFTest, exit(new Exception("Invalid result of getState command")); } else { - resume(sc); + resume(id); } } else { @@ -458,7 +457,7 @@ class TestRCBP1 implements ITCFTest, if (error != null) exit(error); } }); - for (SuspendedContext s : suspended.values()) resume(s); + for (SuspendedContext s : suspended.values()) resume(s.id); } }); } @@ -538,7 +537,12 @@ class TestRCBP1 implements ITCFTest, } public void contextResumed(String id) { - if (threads.get(id) == null) return; + IRunControl.RunControlContext ctx = threads.get(id); + if (ctx == null) return; + if (!ctx.hasState()) { + exit(new Exception("Resumed event for context that HasState = false")); + return; + } SuspendedContext sc = suspended.remove(id); if (isMyBreakpoint(sc)) suspended_prev.put(id, sc); running.add(id); @@ -569,8 +573,13 @@ class TestRCBP1 implements ITCFTest, return false; } - public void contextSuspended(String id, String pc, String reason, Map<String, Object> params) { - if (threads.get(id) == null) return; + public void contextSuspended(final String id, String pc, String reason, Map<String, Object> params) { + IRunControl.RunControlContext ctx = threads.get(id); + if (ctx == null) return; + if (!ctx.hasState()) { + exit(new Exception("Suspended event for context that HasState = false")); + return; + } running.remove(id); SuspendedContext sc = suspended.get(id); if (sc != null) { @@ -591,7 +600,7 @@ class TestRCBP1 implements ITCFTest, main_thread_id = id; } if (main_thread_id == null) { - resume(sc); + resume(id); return; } if (isMyBreakpoint(sc)) { @@ -619,10 +628,19 @@ class TestRCBP1 implements ITCFTest, final SuspendedContext sc0 = sc; ILineNumbers.DoneMapToSource ln_done = new ILineNumbers.DoneMapToSource() { public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) { - if (error != null) exit(error); - else if (mm != null) runMemoryTest(sc0); - else if (rg != null) runRegistersTest(sc0); - else resume(sc0); + if (error != null) { + exit(error); + return; + } + runMemoryTest(sc0, new Runnable() { + public void run() { + runRegistersTest(sc0, new Runnable() { + public void run() { + resume(id); + } + }); + } + }); } }; if (ln != null) { @@ -635,27 +653,27 @@ class TestRCBP1 implements ITCFTest, } } - private void resume(final SuspendedContext sc) { + private void resume(final String id) { assert done_starting_test_process || resume_cnt == 0; if (!done_starting_test_process) return; resume_cnt++; - IRunControl.RunControlContext ctx = threads.get(sc.id); - if (ctx != null && !sc.resumed) { - sc.resumed = true; + SuspendedContext sc = suspended.get(id); + IRunControl.RunControlContext ctx = threads.get(id); + if (ctx != null && sc != null) { ctx.resume(IRunControl.RM_RESUME, 1, new HashMap<String,Object>(), new IRunControl.DoneCommand() { public void doneCommand(IToken token, Exception error) { if (test_suite.cancel) return; if (!test_suite.isActive(TestRCBP1.this)) return; - if (threads.get(sc.id) == null) return; + if (threads.get(id) == null) return; if (error != null) exit(error); } }); } } - private void runMemoryTest(final SuspendedContext sc) { - if (test_suite.target_lock) { - resume(sc); + private void runMemoryTest(final SuspendedContext sc, final Runnable done) { + if (mm == null || test_suite.target_lock) { + Protocol.invokeLater(done); return; } test_suite.target_lock = true; @@ -703,7 +721,7 @@ class TestRCBP1 implements ITCFTest, if (mem_address.longValue() == 0) { exit(new Exception("Bad value of 'tcf_test_array': " + mem_address)); } - testSetMemoryCommand(sc, mem_ctx, mem_address, buf); + testSetMemoryCommand(sc, mem_ctx, mem_address, buf, done); } }); } @@ -712,7 +730,8 @@ class TestRCBP1 implements ITCFTest, private void testSetMemoryCommand(final SuspendedContext sc, final IMemory.MemoryContext mem_ctx, - final Number addr, final byte[] buf) { + final Number addr, final byte[] buf, + final Runnable done) { final byte[] data = new byte[buf.length]; new Random().nextBytes(data); mem_ctx.set(addr, 1, data, 0, data.length, 0, new IMemory.DoneMemory() { @@ -743,7 +762,7 @@ class TestRCBP1 implements ITCFTest, return; } } - testFillMemoryCommand(sc, mem_ctx, addr, buf); + testFillMemoryCommand(sc, mem_ctx, addr, buf, done); } }); } @@ -752,7 +771,8 @@ class TestRCBP1 implements ITCFTest, private void testFillMemoryCommand(final SuspendedContext sc, final IMemory.MemoryContext mem_ctx, - final Number addr, final byte[] buf) { + final Number addr, final byte[] buf, + final Runnable done) { final byte[] data = new byte[buf.length / 7]; new Random().nextBytes(data); mem_ctx.fill(addr, 1, data, buf.length, 0, new IMemory.DoneMemory() { @@ -784,15 +804,18 @@ class TestRCBP1 implements ITCFTest, } } test_suite.target_lock = false; - if (rg != null) runRegistersTest(sc); - else resume(sc); + done.run(); } }); } }); } - private void runRegistersTest(final SuspendedContext sc) { + private void runRegistersTest(final SuspendedContext sc, final Runnable done) { + if (rg == null) { + Protocol.invokeLater(done); + return; + } if (regs.get(sc.id) == null) { final Map<String,IRegisters.RegistersContext> reg_map = new HashMap<String,IRegisters.RegistersContext>(); @@ -828,7 +851,7 @@ class TestRCBP1 implements ITCFTest, } reg_map.put(id, context); if (cmds.isEmpty()) { - testGetSetRegisterCommands(sc); + testGetSetRegisterCommands(sc, done); } } })); @@ -837,11 +860,11 @@ class TestRCBP1 implements ITCFTest, })); } else { - testGetSetRegisterCommands(sc); + testGetSetRegisterCommands(sc, done); } } - private void testGetSetRegisterCommands(final SuspendedContext sc) { + private void testGetSetRegisterCommands(final SuspendedContext sc, final Runnable done) { final Set<IToken> cmds = new HashSet<IToken>(); Map<String,IRegisters.RegistersContext> reg_map = regs.get(sc.id); for (final IRegisters.RegistersContext ctx : reg_map.values()) { @@ -866,7 +889,7 @@ class TestRCBP1 implements ITCFTest, return; } if (cmds.isEmpty()) { - resume(sc); + done.run(); } } })); @@ -906,7 +929,7 @@ class TestRCBP1 implements ITCFTest, return; } if (cmds.isEmpty()) { - resume(sc); + done.run(); } } })); @@ -914,7 +937,7 @@ class TestRCBP1 implements ITCFTest, })); } if (cmds.isEmpty()) { - resume(sc); + done.run(); } } diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRegisters.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRegisters.java index 0f84629d7..0bcacf4ee 100644 --- a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRegisters.java +++ b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFRegisters.java @@ -395,7 +395,6 @@ public class TCFDSFRegisters extends AbstractDsfService implements org.eclipse.d final IDMContext[] parents; Map<String,ObjectDMC> dmc_pool = new HashMap<String,ObjectDMC>();; - boolean disposed; public RegisterChildrenCache(IChannel channel, String id, IDMContext[] parents) { super(channel); @@ -410,18 +409,16 @@ public class TCFDSFRegisters extends AbstractDsfService implements org.eclipse.d } } - void dispose() { - assert !disposed; - reset(); + @Override + public void dispose() { + super.dispose(); for (ObjectDMC dmc : dmc_pool.values()) dmc.dispose(); dmc_pool.clear(); - disposed = true; } @Override public boolean startDataRetrieval() { assert command == null; - assert !disposed; if (tcf_reg_service == null) { reset(null); return true; @@ -484,8 +481,6 @@ public class TCFDSFRegisters extends AbstractDsfService implements org.eclipse.d final org.eclipse.tm.tcf.services.IRegisters.RegistersContext context; final String fmt; - boolean disposed; - public RegisterValueCache(IChannel channel, org.eclipse.tm.tcf.services.IRegisters.RegistersContext context, String fmt) { super(channel); @@ -498,7 +493,6 @@ public class TCFDSFRegisters extends AbstractDsfService implements org.eclipse.d assert command == null; assert tcf_reg_service != null; assert context != null; - assert !disposed; command = context.get(new org.eclipse.tm.tcf.services.IRegisters.DoneGet() { public void doneGet(IToken token, Exception err, byte[] value) { if (command != token) return; @@ -536,12 +530,6 @@ public class TCFDSFRegisters extends AbstractDsfService implements org.eclipse.d }); return false; } - - void dispose() { - assert !disposed; - reset(); - disposed = true; - } } private static class RegisterGroupChangedEvent extends AbstractDMEvent<IRegisterGroupDMContext> diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java index c7e10f766..f002f1f0f 100644 --- a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java +++ b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFStack.java @@ -262,9 +262,6 @@ public class TCFDSFStack extends AbstractDsfService implements IStack { dmc.source_cache.reset(); } } - - void dispose() { - } } private final IChannel channel; |