Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2011-03-09 19:17:02 +0000
committereutarass2011-03-09 19:17:02 +0000
commit2725a676a7cff119f25bbd03872736eeaf8e2f37 (patch)
tree793f568cec766f76bb0197bdd55f20df44abee4f
parent2cf73697cb791a3581c7f2bee6df87e44be08d86 (diff)
downloadorg.eclipse.tcf-2725a676a7cff119f25bbd03872736eeaf8e2f37.tar.gz
org.eclipse.tcf-2725a676a7cff119f25bbd03872736eeaf8e2f37.tar.xz
org.eclipse.tcf-2725a676a7cff119f25bbd03872736eeaf8e2f37.zip
Bug 339216: Add support for foreign breakpoints
-rw-r--r--plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFBreakpointStatusListener.java151
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java34
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelPresentation.java9
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java34
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java28
5 files changed, 216 insertions, 40 deletions
diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFBreakpointStatusListener.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFBreakpointStatusListener.java
index 58bce0e40..7063c2d27 100644
--- a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFBreakpointStatusListener.java
+++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/TCFBreakpointStatusListener.java
@@ -17,35 +17,58 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.debug.core.model.ICBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
+import org.eclipse.cdt.debug.internal.core.breakpoints.CAddressBreakpoint;
+import org.eclipse.cdt.debug.internal.core.breakpoints.CFunctionBreakpoint;
+import org.eclipse.cdt.debug.internal.core.breakpoints.CLineBreakpoint;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.WorkspaceJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tm.internal.tcf.debug.model.ITCFBreakpointListener;
+import org.eclipse.tm.internal.tcf.debug.model.ITCFConstants;
import org.eclipse.tm.internal.tcf.debug.model.TCFBreakpointsModel;
import org.eclipse.tm.internal.tcf.debug.model.TCFBreakpointsStatus;
import org.eclipse.tm.internal.tcf.debug.model.TCFLaunch;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModel;
import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModelManager;
+import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.services.IBreakpoints;
/**
* This class monitors breakpoints status on TCF debug targets and calls ICBreakpoint.incrementInstallCount() or
* ICBreakpoint.decrementInstallCount() when breakpoint status changes.
*/
+@SuppressWarnings("restriction")
class TCFBreakpointStatusListener {
+ /** Ref count attribute for foreign breakpoints */
+ private static final String ATTR_REFCOUNT = "org.eclipse.tm.tcf.cdt.refcount";
+
private class BreakpointListener implements ITCFBreakpointListener {
+ private final TCFLaunch launch;
private final TCFBreakpointsStatus status;
- private final Set<ICBreakpoint> installed;
+ private final Set<ICBreakpoint> installed = new HashSet<ICBreakpoint>();
+ private final Set<String> foreign = new HashSet<String>();
+ private final Set<String> deleted = new HashSet<String>();
BreakpointListener(TCFLaunch launch) {
+ this.launch = launch;
status = launch.getBreakpointsStatus();
status.addListener(this);
bp_listeners.put(launch, this);
- installed = new HashSet<ICBreakpoint>();
for (String id : status.getStatusIDs()) breakpointStatusChanged(id);
}
@@ -71,6 +94,10 @@ class TCFBreakpointStatusListener {
if (installed.remove(cbp)) decrementInstallCount(cbp);
}
}
+ else if (bp == null && foreign.add(id)) {
+ // foreign bp
+ createTransientBreakpoint(id);
+ }
}
public void breakpointRemoved(String id) {
@@ -79,11 +106,18 @@ class TCFBreakpointStatusListener {
ICBreakpoint cbp = (ICBreakpoint)bp;
if (installed.remove(cbp)) decrementInstallCount(cbp);
}
+ if (foreign.remove(id)) {
+ deleteTransientBreakpoint(id);
+ }
}
-
+
void dispose() {
for (ICBreakpoint cbp : installed) decrementInstallCount(cbp);
installed.clear();
+ for (String id : foreign) {
+ deleteTransientBreakpoint(id);
+ }
+ foreign.clear();
}
private void incrementInstallCount(final ICBreakpoint cbp) {
@@ -112,6 +146,117 @@ class TCFBreakpointStatusListener {
});
}
+ private void createTransientBreakpoint(final String id) {
+ IBreakpoints bkpts = launch.getService(IBreakpoints.class);
+ if (bkpts == null) return;
+ bkpts.getProperties(id, new IBreakpoints.DoneGetProperties() {
+ public void doneGetProperties(IToken token, Exception error, Map<String, Object> properties) {
+ final Map<String, Object> markerAttrs = new HashMap<String, Object>();
+ if (properties != null) {
+ String location = (String) properties.get(IBreakpoints.PROP_LOCATION);
+ if (location != null && location.length() > 0) {
+ if (Character.isDigit(location.charAt(0))) {
+ markerAttrs.put(ICLineBreakpoint.ADDRESS, location);
+ }
+ else {
+ markerAttrs.put(ICLineBreakpoint.FUNCTION, location);
+ }
+ }
+ Object file = properties.get(IBreakpoints.PROP_FILE);
+ if (file != null) {
+ markerAttrs.put(ICBreakpoint.SOURCE_HANDLE, file);
+ }
+ Object line = properties.get(IBreakpoints.PROP_LINE);
+ if (line != null) {
+ markerAttrs.put(IMarker.LINE_NUMBER, line);
+ }
+ Object enabled = properties.get(IBreakpoints.PROP_ENABLED);
+ if (enabled != null) {
+ markerAttrs.put(IBreakpoint.ENABLED, enabled);
+ }
+ markerAttrs.put(IBreakpoint.ID, ITCFConstants.ID_TCF_DEBUG_MODEL);
+ markerAttrs.put(IBreakpoint.REGISTERED, Boolean.TRUE);
+ markerAttrs.put(IBreakpoint.PERSISTED, Boolean.FALSE);
+ markerAttrs.put(IMarker.TRANSIENT, Boolean.TRUE);
+ markerAttrs.put(ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, id);
+ markerAttrs.put(ATTR_REFCOUNT, 1);
+ }
+ Job job = new WorkspaceJob("Create Breakpoint Marker") {
+ @Override
+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
+ if (deleted.remove(id)) return Status.OK_STATUS;
+ IBreakpoint[] bps = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
+ for (IBreakpoint bp : bps) {
+ if (bp.isPersisted()) continue;
+ IMarker marker = bp.getMarker();
+ if (marker == null) continue;
+ if (id.equals(marker.getAttribute(ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, null))) {
+ int cnt = marker.getAttribute(ATTR_REFCOUNT, 0) + 1;
+ marker.setAttribute(ATTR_REFCOUNT, cnt);
+ return Status.OK_STATUS;
+ }
+ }
+ IResource resource = ResourcesPlugin.getWorkspace().getRoot();
+ if (markerAttrs.get(ICBreakpoint.SOURCE_HANDLE) != null &&
+ markerAttrs.get(IMarker.LINE_NUMBER) != null) {
+ new CLineBreakpoint(resource , markerAttrs, true);
+ } else if (markerAttrs.get(ICLineBreakpoint.ADDRESS) != null) {
+ new CAddressBreakpoint(resource, markerAttrs, true);
+ } else if (markerAttrs.get(ICLineBreakpoint.FUNCTION) != null) {
+ new CFunctionBreakpoint(resource, markerAttrs, true);
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.setRule(getBreakpointAccessRule());
+ job.schedule();
+ }
+ });
+ }
+
+ private void deleteTransientBreakpoint(final String id) {
+ Job job = new WorkspaceJob("Destroy Breakpoint Marker") {
+ @Override
+ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
+ IBreakpoint[] bps = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
+ for (IBreakpoint bp : bps) {
+ if (bp.isPersisted()) continue;
+ IMarker marker = bp.getMarker();
+ if (marker == null) continue;
+ if (id.equals(marker.getAttribute(ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, null))) {
+ int cnt = marker.getAttribute(ATTR_REFCOUNT, 0) - 1;
+ if (cnt > 0) {
+ marker.setAttribute(ATTR_REFCOUNT, cnt);
+ }
+ else {
+ bp.delete();
+ }
+ return Status.OK_STATUS;
+ }
+ }
+ // Since breakpoint object is created by a another background job after reading data from remote peer,
+ // this job can be running before the job that creates the object.
+ // We need to remember ID of the breakpoint that became obsolete before it was fully created.
+ deleted.add(id);
+ return Status.OK_STATUS;
+ }
+ };
+ job.setRule(getBreakpointAccessRule());
+ job.schedule();
+ }
+
+ private ISchedulingRule getBreakpointAccessRule() {
+ IResource resource = ResourcesPlugin.getWorkspace().getRoot();
+ ISchedulingRule rule = ResourcesPlugin.getWorkspace().getRuleFactory().markerRule(resource);
+ if (rule == null) {
+ // In Eclipse 3.6.2, markerRule() always returns null,
+ // causing race condition, a lot of crashes and corrupted data.
+ // Using modifyRule() instead.
+ rule = ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(resource);
+ }
+ return rule;
+ }
+
private void asyncExec(Runnable r) {
synchronized (Device.class) {
Display display = Display.getDefault();
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
index 304f7efca..3a6e37c8f 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
@@ -284,30 +284,24 @@ public class TCFAnnotationManager {
}
String getBreakpointStatus(final TCFBreakpoint breakpoint) {
- if (disposed) return "";
- assert Thread.currentThread() == display.getThread();
+ assert Protocol.isDispatchThread();
+ if (disposed) return null;
final TCFLaunch launch = active_launch;
- final String[] text = new String[1];
- text[0] = breakpoint.getText();
if (launch != null && launch.getBreakpointsStatus() != null) {
- Protocol.invokeAndWait(new Runnable() {
- public void run() {
- TCFBreakpointsStatus bs = launch.getBreakpointsStatus();
- if (bs != null) {
- Map<String,Object> map = bs.getStatus(breakpoint);
- if (map != null) {
- String status = null;
- String error = (String)map.get(IBreakpoints.STATUS_ERROR);
- Object planted = map.get(IBreakpoints.STATUS_INSTANCES);
- if (error != null) status = error;
- else if (planted != null) status = "Planted";
- if (status != null) text[0] += " (" + status + ")";
- }
- }
+ TCFBreakpointsStatus bs = launch.getBreakpointsStatus();
+ if (bs != null) {
+ Map<String,Object> map = bs.getStatus(breakpoint);
+ if (map != null) {
+ String status = null;
+ String error = (String)map.get(IBreakpoints.STATUS_ERROR);
+ Object planted = map.get(IBreakpoints.STATUS_INSTANCES);
+ if (error != null) status = error;
+ else if (planted != null) status = "Planted";
+ return status;
}
- });
+ }
}
- return text[0];
+ return null;
}
void addStackFrameAnnotation(TCFModel model, String exe_id, boolean top_frame,
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelPresentation.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelPresentation.java
index 392d5b570..b74b009ed 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelPresentation.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelPresentation.java
@@ -31,6 +31,7 @@ import org.eclipse.swt.graphics.Image;
import org.eclipse.tm.internal.tcf.debug.model.TCFBreakpoint;
import org.eclipse.tm.internal.tcf.debug.ui.Activator;
import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
+import org.eclipse.tm.tcf.util.TCFTask;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorRegistry;
@@ -84,9 +85,13 @@ public class TCFModelPresentation implements IDebugModelPresentation {
public String getText(Object element) {
String text = null;
if (element instanceof TCFBreakpoint) {
- TCFBreakpoint breakpoint = (TCFBreakpoint)element;
+ final TCFBreakpoint breakpoint = (TCFBreakpoint)element;
text = breakpoint.getText();
- String status = Activator.getAnnotationManager().getBreakpointStatus(breakpoint);
+ String status = new TCFTask<String>() {
+ public void run() {
+ done(Activator.getAnnotationManager().getBreakpointStatus(breakpoint));
+ }
+ }.getE();
if (status != null) text += " (" + status + ")";
}
return text;
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java
index e769d507c..8acbc4f73 100644
--- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java
@@ -11,9 +11,11 @@
package org.eclipse.tm.internal.tcf.debug.model;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -119,23 +121,27 @@ public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointMana
});
IBreakpoint[] arr = bp_manager.getBreakpoints();
if (arr != null && arr.length > 0) {
- Map<String,Object>[] bps = new Map[arr.length];
+ List<Map<String,Object>> bps = new ArrayList<Map<String,Object>>(arr.length);
for (int i = 0; i < arr.length; i++) {
if (!isSupported(channel, arr[i])) continue;
String id = getBreakpointID(arr[i]);
if (id == null) continue;
+ if (!arr[i].isPersisted()) continue;
IMarker marker = arr[i].getMarker();
String file = getFilePath(marker.getResource());
- bps[i] = toBreakpointAttributes(id, file, marker.getType(), marker.getAttributes());
+ bps.add(toBreakpointAttributes(id, file, marker.getType(), marker.getAttributes()));
id2bp.put(id, arr[i]);
}
- service.set(bps, new IBreakpoints.DoneCommand() {
- public void doneCommand(IToken token, Exception error) {
- if (error == null) done.run();
- else channel.terminate(error);
- }
- });
- return;
+ if (!bps.isEmpty()) {
+ Map<String, Object>[] bpArr = (Map<String,Object>[]) bps.toArray(new Map[bps.size()]);
+ service.set(bpArr, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error == null) done.run();
+ else channel.terminate(error);
+ }
+ });
+ return;
+ }
}
}
Protocol.invokeLater(done);
@@ -200,7 +206,7 @@ public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointMana
private abstract class BreakpointUpdate implements Runnable {
private final IBreakpoint breakpoint;
- private final Map<String,Object> marker_attrs;
+ protected final Map<String,Object> marker_attrs;
private final String marker_file;
private final String marker_type;
private final String marker_id;
@@ -263,7 +269,9 @@ public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointMana
new BreakpointUpdate(breakpoint) {
@Override
void update() {
- service.add(tcf_attrs, done);
+ if (!Boolean.FALSE.equals(marker_attrs.get(IBreakpoint.PERSISTED))) {
+ service.add(tcf_attrs, done);
+ }
id2bp.put((String)tcf_attrs.get(IBreakpoints.PROP_ID), breakpoint);
}
}.exec();
@@ -332,7 +340,9 @@ public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointMana
@Override
void update() {
String id = (String)tcf_attrs.get(IBreakpoints.PROP_ID);
- service.remove(new String[]{ id }, done);
+ if (!Boolean.FALSE.equals(marker_attrs.get(IBreakpoint.PERSISTED))) {
+ service.remove(new String[]{ id }, done);
+ }
id2bp.remove(id);
}
}.exec();
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java
index 486101843..31dce0a2b 100644
--- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 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
@@ -18,6 +18,7 @@ import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IBreakpoints;
@@ -38,7 +39,7 @@ public class TCFBreakpointsStatus {
assert Protocol.isDispatchThread();
service = launch.getChannel().getRemoteService(IBreakpoints.class);
if (service != null) {
- service.addListener(new IBreakpoints.BreakpointsListener() {
+ final IBreakpoints.BreakpointsListener listener = new IBreakpoints.BreakpointsListener() {
public void breakpointStatusChanged(String id, Map<String,Object> m) {
assert Protocol.isDispatchThread();
@@ -65,10 +66,31 @@ public class TCFBreakpointsStatus {
public void contextRemoved(String[] ids) {
for (String id : ids) {
- if (status.remove(id) == null) continue;
+ if (!status.containsKey(id)) continue;
for (Iterator<ITCFBreakpointListener> i = listeners.iterator(); i.hasNext();) {
i.next().breakpointRemoved(id);
}
+ status.remove(id);
+ }
+ }
+ };
+ service.addListener(listener);
+
+ // query foreign breakpoints
+ service.getIDs(new IBreakpoints.DoneGetIDs() {
+ @SuppressWarnings("unchecked")
+ public void doneGetIDs(IToken token, Exception error, String[] ids) {
+ if (error != null) return;
+ for (final String id : ids) {
+ // fake properties - only ID is required for contextAdded
+ Map<String, Object> bpProps = new HashMap<String, Object>();
+ bpProps.put(IBreakpoints.PROP_ID, id);
+ listener.contextAdded((Map<String, Object>[]) new Map[] { bpProps });
+ service.getStatus(id, new IBreakpoints.DoneGetStatus() {
+ public void doneGetStatus(IToken token, Exception error, Map<String, Object> status) {
+ if (error == null) listener.breakpointStatusChanged(id, status);
+ }
+ });
}
}
});

Back to the top