diff options
author | eutarass | 2011-03-09 19:17:02 +0000 |
---|---|---|
committer | eutarass | 2011-03-09 19:17:02 +0000 |
commit | 2725a676a7cff119f25bbd03872736eeaf8e2f37 (patch) | |
tree | 793f568cec766f76bb0197bdd55f20df44abee4f | |
parent | 2cf73697cb791a3581c7f2bee6df87e44be08d86 (diff) | |
download | org.eclipse.tcf-2725a676a7cff119f25bbd03872736eeaf8e2f37.tar.gz org.eclipse.tcf-2725a676a7cff119f25bbd03872736eeaf8e2f37.tar.xz org.eclipse.tcf-2725a676a7cff119f25bbd03872736eeaf8e2f37.zip |
Bug 339216: Add support for foreign breakpoints
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); + } + }); } } }); |