# HG changeset patch # User l12wang # Date 1258959556 21600 # Node ID 09f3d307f0818cf43a49dc2b74e40374970964e2 # Parent 05ea843f7d56e1a2e7ad19ae01495d69b346940f Overhauled BreakpointsMediator to support both EDC and GDB properly. See Eclipse bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=292468 diff -r 05ea843f7d56 -r 09f3d307f081 cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointAttributeTranslator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointAttributeTranslator.java Mon Nov 23 00:59:16 2009 -0600 @@ -0,0 +1,561 @@ +/******************************************************************************* + * Copyright (c) 2009 Nokia and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Nokia - Initial API and implementation. Nov, 2009. + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.cdt.debug.core.model.ICBreakpoint; +import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; +import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; +import org.eclipse.cdt.debug.core.model.ICWatchpoint; +import org.eclipse.cdt.debug.internal.core.breakpoints.BreakpointProblems; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator; +import org.eclipse.cdt.dsf.debug.service.IBreakpointAttributeTranslatorExtension; +import org.eclipse.cdt.dsf.debug.service.IDsfBreakpointExtension; +import org.eclipse.cdt.dsf.debug.service.ISourceLookup; +import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator.BreakpointEventType; +import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator.ITargetBreakpointInfo; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IBreakpoint; + +public class MIBreakpointAttributeTranslator implements IBreakpointAttributeTranslatorExtension { + + private final static String GDB_DEBUG_MODEL_ID = "org.eclipse.cdt.dsf.gdb"; //$NON-NLS-1$ + + // Extra breakpoint attributes + private static final String ATTR_DEBUGGER_PATH = GdbPlugin.PLUGIN_ID + ".debuggerPath"; //$NON-NLS-1$ + private static final String ATTR_THREAD_FILTER = GdbPlugin.PLUGIN_ID + ".threadFilter"; //$NON-NLS-1$ +// private static final String ATTR_THREAD_ID = GdbPlugin.PLUGIN_ID + ".threadID"; //$NON-NLS-1$ + + private DsfServicesTracker dsfServicesTracker; + private DsfSession dsfSession; + private BreakpointsMediator breakpointsMediator; + private String debugModelId; + + /** + * Manage breakpoint problem markers.
+ * It's better be done by MIBreakpoints service so that it's accessible by + * the MIBreakpoints service too. But to minimize change to MIBreakpoints in + * this iteration, I just put it here..... 11/18/09 + */ + private Map fBreakpointMarkerProblems = + new HashMap(); + + public MIBreakpointAttributeTranslator(DsfSession dsfSession, String debugModelId) { + super(); + this.dsfSession = dsfSession; + this.debugModelId = debugModelId; + + dsfServicesTracker = new DsfServicesTracker(GdbPlugin.getDefault().getBundle().getBundleContext(), dsfSession.getId()); + } + + public boolean canUpdateAttributes(IBreakpointDMContext bp, Map delta) { + /* + * This method decides whether we need to re-install the breakpoint + * based on the attributes change (refer to caller in + * BreakpointsMediator). + */ + // Check if there is any modified attribute + if (delta == null || delta.size() == 0) + return true; + + // Check the "critical" attributes + if (delta.containsKey(ATTR_DEBUGGER_PATH) // File name + || delta.containsKey(MIBreakpoints.LINE_NUMBER) // Line number + || delta.containsKey(MIBreakpoints.FUNCTION) // Function name + || delta.containsKey(MIBreakpoints.ADDRESS) // Absolute address + || delta.containsKey(ATTR_THREAD_FILTER) // Thread ID + || delta.containsKey(MIBreakpoints.EXPRESSION) // Watchpoint expression + || delta.containsKey(MIBreakpoints.READ) // Watchpoint type + || delta.containsKey(MIBreakpoints.WRITE)) { // Watchpoint type + return false; + } + + // for other attrs (ICBreakpoint.INSTALL_COUNT, ICBreakpoint.IGNORE_COUNT, + // ICBreakpoint.CONDITION, etc), we can update them. + return true; + } + + public void dispose() { + if (dsfServicesTracker != null) + dsfServicesTracker.dispose(); + dsfSession = null; + + clearBreakpointProblemMarkers(); + } + + public List> getBreakpointAttributes(IBreakpoint bp, boolean bpManagerEnabled) + throws CoreException { + // deprecated + List> retVal = new ArrayList>(); + return retVal; + } + + public void initialize(BreakpointsMediator mediator) { + breakpointsMediator = mediator; + } + + public boolean supportsBreakpoint(IBreakpoint bp) { + if (bp instanceof ICBreakpoint && bp.getModelIdentifier().equals(debugModelId)) { + IMarker marker = bp.getMarker(); + if (marker != null) { + return true; + } + } + return false; + } + + public void updateBreakpointStatus(IBreakpoint bp) { + // obsolet, do nothing. + } + + public void updateBreakpointsStatus(Map> bpsInfo, + BreakpointEventType eventType) { + for (IBreakpoint bp : bpsInfo.keySet()) { + if (! (bp instanceof ICBreakpoint)) // not C breakpoints, bail out. + return; + + final ICBreakpoint icbp = (ICBreakpoint) bp; + + Map targetBpPerContext = bpsInfo.get(bp); + + switch (eventType) { + case ADDED: { + int installCountTotal = 0; + StringBuffer errMsg = new StringBuffer(); + for (ITargetBreakpointInfo[] tbpInfos : targetBpPerContext.values()) { + // For each BpTargetDMContext, we increment the installCount for each + // target BP that has been successfully installed. + int installCountPerContext = 0; + for (ITargetBreakpointInfo tbp : tbpInfos) { + if (tbp.getTargetBreakpoint() != null) + installCountPerContext++; + else // failure in installation + errMsg.append(tbp.getStatus().getMessage()).append('\n'); + } + installCountTotal += installCountPerContext; + } + + for (int i=0; i < installCountTotal; i++) + try { + // this will eventually carried out in a workspace runnable. + icbp.incrementInstallCount(); + } catch (CoreException e) { + GdbPlugin.getDefault().getLog().log(e.getStatus()); + } + + if (errMsg.length() > 0) + addBreakpointProblemMarker(icbp, errMsg.toString(), IMarker.SEVERITY_WARNING); + else // no error, clean message if any. + removeBreakpointProblemMarker(icbp); + + break; + } + case MODIFIED: + break; + + case REMOVED: { + int removeCountTotal = 0; + for (ITargetBreakpointInfo[] tbpInfos : targetBpPerContext.values()) { + // For each BpTargetDMContext, we decrement the installCount for each + // target BP that we tried to remove, even if the removal failed. That's + // because I've not seen a way to tell platform that removal fails + // and the BP should be kept in UI. + removeCountTotal += tbpInfos.length; + } + + for (int i=0; i < removeCountTotal; i++) + try { + if (icbp.isRegistered()) // not deleted in UI + icbp.decrementInstallCount(); + } catch (CoreException e) { + GdbPlugin.getDefault().getLog().log(e.getStatus()); + } + break; + } + } + } + } + + public Map convertAttributes(Map platformAttrs) { + Map targetAttrs = new HashMap(); + + if (platformAttrs.containsKey(MIBreakpoints.BREAKPOINT_TYPE)) + targetAttrs.put(MIBreakpoints.BREAKPOINT_TYPE, platformAttrs.get(MIBreakpoints.BREAKPOINT_TYPE)); + + if (platformAttrs.containsKey(ICWatchpoint.EXPRESSION)) + targetAttrs.put(MIBreakpoints.EXPRESSION, platformAttrs.get(ICWatchpoint.EXPRESSION)); + if (platformAttrs.containsKey(ICWatchpoint.READ)) + targetAttrs.put(MIBreakpoints.READ, platformAttrs.get(ICWatchpoint.READ)); + if (platformAttrs.containsKey(ICWatchpoint.WRITE)) + targetAttrs.put(MIBreakpoints.WRITE, platformAttrs.get(ICWatchpoint.WRITE)); + + if (platformAttrs.containsKey(ICBreakpoint.SOURCE_HANDLE)) + targetAttrs.put(MIBreakpoints.FILE_NAME, platformAttrs.get(ICBreakpoint.SOURCE_HANDLE)); + + if (platformAttrs.containsKey(IMarker.LINE_NUMBER)) + targetAttrs.put(MIBreakpoints.LINE_NUMBER, platformAttrs.get(IMarker.LINE_NUMBER)); + if (platformAttrs.containsKey(ICLineBreakpoint.FUNCTION)) + targetAttrs.put(MIBreakpoints.FUNCTION, platformAttrs.get(ICLineBreakpoint.FUNCTION)); + if (platformAttrs.containsKey(ICLineBreakpoint.ADDRESS)) + targetAttrs.put(MIBreakpoints.ADDRESS, platformAttrs.get(ICLineBreakpoint.ADDRESS)); + + if (platformAttrs.containsKey(ICBreakpoint.CONDITION)) + targetAttrs.put(MIBreakpoints.CONDITION, platformAttrs.get(ICBreakpoint.CONDITION)); + if (platformAttrs.containsKey(ICBreakpoint.IGNORE_COUNT)) + targetAttrs.put(MIBreakpoints.IGNORE_COUNT, platformAttrs.get(ICBreakpoint.IGNORE_COUNT)); + if (platformAttrs.containsKey(ICBreakpoint.ENABLED)) + targetAttrs.put(MIBreakpoints.IS_ENABLED, platformAttrs.get(ICBreakpoint.ENABLED)); + + return targetAttrs; + } + + @SuppressWarnings("unchecked") + public void resolveBreakpoint(IBreakpointsTargetDMContext context, IBreakpoint breakpoint, + Map bpAttributes, final DataRequestMonitor>> drm) { + + assert dsfSession.getExecutor().isInExecutorThread(); + + // Create a copy as we don't want to change "bpAttributes". + final Map targetBPAttrBase = new HashMap(bpAttributes); + + final Set threads = (Set) targetBPAttrBase.get(ATTR_THREAD_FILTER); + + final List> targetBPList = new ArrayList>(); + + // get debugger path (compilation-path) for source file, if any. + determineDebuggerPath(context, targetBPAttrBase, new RequestMonitor(dsfSession.getExecutor(), drm){ + @Override + protected void handleSuccess() { + // Create attribute list for each thread + for (String thread : threads) { + Map targetBP = new HashMap(targetBPAttrBase); + targetBP.put(MIBreakpointDMData.THREAD_ID, thread); + targetBPList.add(targetBP); + } + + drm.setData(targetBPList); + drm.done(); + }}); + } + + /** + * determineDebuggerPath + * + * Adds the path to the source file to the set of attributes + * (for the debugger). + * + * @param dmc + * @param targetAttrs + * @param rm + */ + private void determineDebuggerPath(IBreakpointsTargetDMContext dmc, + final Map targetAttrs, final RequestMonitor rm) + { + String hostPath = (String) targetAttrs.get(MIBreakpoints.FILE_NAME); + + if (hostPath != null) { + ISourceLookup sourceService = dsfServicesTracker.getService(ISourceLookup.class); + + ISourceLookupDMContext srcDmc = DMContexts.getAncestorOfType(dmc, ISourceLookupDMContext.class); + if (srcDmc != null) { + sourceService.getDebuggerPath(srcDmc, hostPath, + new DataRequestMonitor(dsfSession.getExecutor(), rm) { + @Override + protected void handleSuccess() { + targetAttrs.put(ATTR_DEBUGGER_PATH, adjustDebuggerPath(getData())); + rm.done(); + } + }); + } else { + // Source lookup not available for given context, use the host + // path for the debugger path. + targetAttrs.put(ATTR_DEBUGGER_PATH, adjustDebuggerPath(hostPath)); + rm.done(); + } + } else { + // Some types of breakpoints do not require a path + // (e.g. watchpoints) + rm.done(); + } + } + + /** + * See bug232415 + * + * @param path the absolute path to the source file + * @return + */ + private String adjustDebuggerPath(String path) { + String result = path; + // Make it MinGW-specific + if (Platform.getOS().startsWith("win")) { //$NON-NLS-1$ + if (!path.startsWith("/")) { //$NON-NLS-1$ + result = path.substring(path.lastIndexOf('\\') + 1); + } + } + return result; + } + + /** + * Get the list of threads from the platform breakpoint attributes + * + * @param context + * if the context is not null, only get threads that are children + * of this context. otherwise get all threads. + * @param breakpoint + * @return + */ + private Set extractThreads(IBreakpointsTargetDMContext context, ICBreakpoint breakpoint) { + Set results = new HashSet(); + + // Find the ancestor + List threads = new ArrayList(1); + + try { + // Retrieve the targets + IDsfBreakpointExtension filterExtension = getFilterExtension(breakpoint); + IContainerDMContext[] targets = filterExtension.getTargetFilters(); + + // If no target is present, breakpoint applies to all. + if (targets.length == 0) { + results.add("0"); //$NON-NLS-1$ + return results; + } + + // Extract the thread IDs (if there is none, we are covered) + for (IContainerDMContext ctxt : targets) { + if (context == null || + DMContexts.isAncestorOf(ctxt, context)) { + threads.add(filterExtension.getThreadFilters(ctxt)); + } + } + } catch (CoreException e1) { + } + + if (supportsThreads(breakpoint)) { + for (IExecutionDMContext[] targetThreads : threads) { + if (targetThreads != null) { + for (IExecutionDMContext thread : targetThreads) { + if (thread instanceof IMIExecutionDMContext) { + IMIExecutionDMContext dmc = (IMIExecutionDMContext) thread; + results.add(((Integer) dmc.getThreadId()).toString()); + } + } + } else { + results.add("0"); //$NON-NLS-1$ + break; + } + } + } else { + results.add("0"); //$NON-NLS-1$ + } + + return results; + } + + /** + * Indicates if the back-end supports multiple threads for + * this type of breakpoint + * + * @param breakpoint + */ + protected boolean supportsThreads(ICBreakpoint breakpoint) { + + return !(breakpoint instanceof ICWatchpoint); + } + + /** + * @param bp + * @return + * @throws CoreException + */ + private IDsfBreakpointExtension getFilterExtension(ICBreakpoint bp) throws CoreException { + return (IDsfBreakpointExtension) bp.getExtension(GDB_DEBUG_MODEL_ID, ICBreakpointExtension.class); + } + + public Map getAllBreakpointAttributes(IBreakpoint breakpoint, boolean bpManagerEnabled) throws CoreException { + + assert ! dsfSession.getExecutor().isInExecutorThread(); + + // Check that the marker exists and retrieve its attributes. + // Due to accepted race conditions, the breakpoint marker may become + // null while this method is being invoked. In this case throw an exception + // and let the caller handle it. + IMarker marker = breakpoint.getMarker(); + if (marker == null || !marker.exists()) { + throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, + "Breakpoint marker does not exist", null)); + } + + // Suppress cast warning: platform is still on Java 1.3 + @SuppressWarnings("unchecked") + Map attributes = marker.getAttributes(); + + Map targetAttrs = convertAttributes(attributes); + + // Determine breakpoint type. + if (breakpoint instanceof ICWatchpoint) + targetAttrs.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.WATCHPOINT); + else if (breakpoint instanceof ICLineBreakpoint) + targetAttrs.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.BREAKPOINT); + else { + // catchpoint? + } + + // Adjust for "skip-all" + if (!bpManagerEnabled) { + targetAttrs.put(MIBreakpoints.IS_ENABLED, false); + } + + Set threads = extractThreads(null, (ICBreakpoint) breakpoint); + targetAttrs.put(ATTR_THREAD_FILTER, threads); + + return targetAttrs; + } + + public boolean canUpdateAttributes(IBreakpoint bp, IBreakpointsTargetDMContext context, Map attrDelta) { + boolean yesWeCan; + + if (attrDelta.containsKey(MIBreakpoints.IS_ENABLED) && bp != null) { + // GDB special: + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=261082 + // + Map delta = new HashMap(attrDelta); + + delta.remove(MIBreakpoints.IS_ENABLED); + + yesWeCan = canUpdateAttributes(null, delta); + + if (yesWeCan) { + // other attribute change indicates we can. Now check the ENABLE. + // if the breakpoint is already installed in the "context" (a process), + // we can. Otherwise no. + ITargetBreakpointInfo[] targetBPs = breakpointsMediator.getTargetBreakpoints(context, bp); + yesWeCan = targetBPs != null && targetBPs.length > 0; + } + } + else + yesWeCan = canUpdateAttributes(null, attrDelta); + + return yesWeCan; + } + + private void addBreakpointProblemMarker(final ICBreakpoint breakpoint, final String description, final int severity) { + + new Job("Add Breakpoint Problem Marker") { //$NON-NLS-1$ + {setSystem(true); }; + + @Override + protected IStatus run(IProgressMonitor monitor) { + + if (breakpoint instanceof ICLineBreakpoint) { + // If we have already have a problem marker on this breakpoint + // we should remove it first. + IMarker marker = fBreakpointMarkerProblems.remove(breakpoint); + if (marker != null) { + try { + marker.delete(); + } catch (CoreException e) { + } + } + + ICLineBreakpoint lineBreakpoint = (ICLineBreakpoint) breakpoint; + try { + // Locate the workspace resource via the breakpoint marker + IMarker breakpoint_marker = lineBreakpoint.getMarker(); + IResource resource = breakpoint_marker.getResource(); + + // Add a problem marker to the resource + IMarker problem_marker = resource.createMarker(BreakpointProblems.BREAKPOINT_PROBLEM_MARKER_ID); + int line_number = lineBreakpoint.getLineNumber(); + problem_marker.setAttribute(IMarker.LOCATION, String.valueOf(line_number)); + problem_marker.setAttribute(IMarker.MESSAGE, description); + problem_marker.setAttribute(IMarker.SEVERITY, severity); + problem_marker.setAttribute(IMarker.LINE_NUMBER, line_number); + + // And save the baby + fBreakpointMarkerProblems.put(breakpoint, problem_marker); + } catch (CoreException e) { + } + } + return Status.OK_STATUS; + } + }.schedule(); + } + + private void removeBreakpointProblemMarker(final ICBreakpoint breakpoint) { + + new Job("Remove Breakpoint Problem Marker") { //$NON-NLS-1$ + {setSystem(true); }; + @Override + protected IStatus run(IProgressMonitor monitor) { + + IMarker marker = fBreakpointMarkerProblems.remove(breakpoint); + if (marker != null) { + try { + marker.delete(); + } catch (CoreException e) { + } + } + + return Status.OK_STATUS; + } + }.schedule(); + } + + /** + */ + private void clearBreakpointProblemMarkers() + { + new Job("Clear Breakpoint problem markers") { //$NON-NLS-1$ + { setSystem(true); }; + @Override + protected IStatus run(IProgressMonitor monitor) { + for (IMarker marker : fBreakpointMarkerProblems.values()) { + if (marker != null) { + try { + marker.delete(); + } catch (CoreException e) { + } + } + } + fBreakpointMarkerProblems.clear(); + return Status.OK_STATUS; + } + }.schedule(); + } +} + \ No newline at end of file diff -r 05ea843f7d56 -r 09f3d307f081 cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java --- a/cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java Tue Nov 17 14:33:45 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java Mon Nov 23 00:59:16 2009 -0600 @@ -15,6 +15,8 @@ import java.util.Hashtable; import java.util.Map; +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.debug.core.model.ICBreakpoint; import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Immutable; @@ -27,6 +29,8 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.mi.service.MIRunControl.SuspendedEvent; +import org.eclipse.cdt.dsf.mi.service.breakpoint.actions.BreakpointActionAdapter; import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakAfter; import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakCondition; import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakDelete; @@ -35,7 +39,9 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakInsert; import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakList; import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakWatch; +import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent; import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointScopeEvent; +import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointTriggerEvent; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; @@ -43,8 +49,11 @@ import org.eclipse.cdt.dsf.service.AbstractDsfService; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; +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.Job; import org.osgi.framework.BundleContext; /** @@ -281,6 +290,53 @@ public void eventDispatched(ICommandControlShutdownDMEvent e) { } + @DsfServiceEventHandler + public void eventDispatched(SuspendedEvent e) { + + if (e.getMIEvent() instanceof MIBreakpointHitEvent) { + MIBreakpointHitEvent evt = (MIBreakpointHitEvent) e.getMIEvent(); + performBreakpointAction(evt.getDMContext(), evt.getNumber()); + return; + } + + if (e.getMIEvent() instanceof MIWatchpointTriggerEvent) { + MIWatchpointTriggerEvent evt = (MIWatchpointTriggerEvent) e.getMIEvent(); + performBreakpointAction(evt.getDMContext(), evt.getNumber()); + return; + } + } + + private void performBreakpointAction(final IDMContext context, int number) { + // Identify the platform breakpoint + final ICBreakpoint breakpoint = findPlatformBreakpoint(context, number); + + // Perform the actions asynchronously (otherwise we can have a deadlock...) + new Job("Breakpoint action") { //$NON-NLS-1$ + { setSystem(true); } + @Override + protected IStatus run(IProgressMonitor monitor) { + CDebugCorePlugin.getDefault().getBreakpointActionManager().executeActions(breakpoint, new BreakpointActionAdapter(getExecutor(), getServicesTracker(), context)); + return Status.OK_STATUS; + }; + }.schedule(); + } + + // Helper function to locate the platform breakpoint corresponding + // to the target breakpoint/watchpoint that was just hit + + // FIXME: (Bug228703) Need a way to identify the correct context where the BP was hit + private ICBreakpoint findPlatformBreakpoint(IDMContext context, int targetBreakpointID) { + // Hmm, the service has no tracking of MIBreakpointDMContext. So this workaround. + IBreakpointsTargetDMContext btDMC = DMContexts.getAncestorOfType(context, IBreakpointsTargetDMContext.class); + assert btDMC != null; + IBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { btDMC }, targetBreakpointID); + + MIBreakpointsManager bpMediator = getServicesTracker().getService(MIBreakpointsManager.class); + ICBreakpoint cdtBP = (ICBreakpoint)bpMediator.getPlatformBreakpoint(btDMC, dmc); + + return cdtBP; + } + /////////////////////////////////////////////////////////////////////////// // IBreakpoints interface /////////////////////////////////////////////////////////////////////////// @@ -763,7 +819,7 @@ // Retrieve the breakpoint parameters // At this point, we know their are OK so there is no need to re-validate MIBreakpointDMContext breakpointCtx = (MIBreakpointDMContext) dmc; - IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); + final IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); final Map contextBreakpoints = fBreakpoints.get(context); final int reference = breakpointCtx.getReference(); MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); @@ -782,11 +838,22 @@ // Determine if the breakpoint condition changed String conditionAttribute = CONDITION; if (properties.containsKey(conditionAttribute)) { - String oldValue = breakpoint.getCondition(); + final String oldValue = breakpoint.getCondition(); String newValue = (String) properties.get(conditionAttribute); if (newValue == null) newValue = NULL_STRING; if (!oldValue.equals(newValue)) { - changeCondition(context, reference, newValue, countingRm); + changeCondition(context, reference, newValue, new RequestMonitor(getExecutor(), countingRm){ + + @Override + protected void handleError() { + // Failed to change the condition, restore the old condition. + // See comment in changeCondition() for more. + MIBreakpointsManager bpMediator = getServicesTracker().getService(MIBreakpointsManager.class); + final ICBreakpoint cdtBP = (ICBreakpoint)bpMediator.getPlatformBreakpoint(context, dmc); + rollbackCondition(cdtBP, oldValue); + + countingRm.done(); + }}); numberOfChanges++; } properties.remove(conditionAttribute); @@ -825,6 +892,26 @@ countingRm.setDoneCount(numberOfChanges); } + private void rollbackCondition(final ICBreakpoint cdtBP, final String oldValue) { + if (cdtBP == null) + return; + + new Job("rollback breakpont condition") { //$NON-NLS-1$ + { setSystem(true); } + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + if (oldValue != null) + cdtBP.setCondition(oldValue); + else + cdtBP.setCondition(NULL_STRING); + } catch (CoreException e) { + // ignore + } + return Status.OK_STATUS; + }}.schedule(); + } + /** * Update the breakpoint condition * diff -r 05ea843f7d56 -r 09f3d307f081 cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsManager.java --- a/cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsManager.java Tue Nov 17 14:33:45 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsManager.java Mon Nov 23 00:59:16 2009 -0600 @@ -15,74 +15,8 @@ package org.eclipse.cdt.dsf.mi.service; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Vector; -import java.util.concurrent.RejectedExecutionException; - -import org.eclipse.cdt.debug.core.CDebugCorePlugin; -import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager; -import org.eclipse.cdt.debug.core.model.ICAddressBreakpoint; -import org.eclipse.cdt.debug.core.model.ICBreakpoint; -import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; -import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; -import org.eclipse.cdt.debug.core.model.ICWatchpoint; -import org.eclipse.cdt.debug.internal.core.breakpoints.BreakpointProblems; -import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; -import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; -import org.eclipse.cdt.dsf.concurrent.DsfRunnable; -import org.eclipse.cdt.dsf.concurrent.RequestMonitor; -import org.eclipse.cdt.dsf.concurrent.ThreadSafe; -import org.eclipse.cdt.dsf.datamodel.DMContexts; -import org.eclipse.cdt.dsf.datamodel.IDMContext; -import org.eclipse.cdt.dsf.debug.service.IBreakpoints; -import org.eclipse.cdt.dsf.debug.service.IDsfBreakpointExtension; -import org.eclipse.cdt.dsf.debug.service.IRunControl; -import org.eclipse.cdt.dsf.debug.service.ISourceLookup; -import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext; -import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; -import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; -import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; -import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; -import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent; -import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; -import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.BreakpointAddedEvent; -import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.BreakpointRemovedEvent; -import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.BreakpointUpdatedEvent; -import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext; -import org.eclipse.cdt.dsf.mi.service.MIRunControl.SuspendedEvent; -import org.eclipse.cdt.dsf.mi.service.breakpoint.actions.BreakpointActionAdapter; -import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent; -import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointScopeEvent; -import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointTriggerEvent; -import org.eclipse.cdt.dsf.service.AbstractDsfService; -import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; +import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator; import org.eclipse.cdt.dsf.service.DsfSession; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRunnable; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.ISchedulingRule; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.core.runtime.jobs.MultiRule; -import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.IBreakpointListener; -import org.eclipse.debug.core.IBreakpointManager; -import org.eclipse.debug.core.IBreakpointManagerListener; -import org.eclipse.debug.core.model.IBreakpoint; -import org.osgi.framework.BundleContext; /** * Breakpoint service interface. The breakpoint service tracks CDT breakpoint @@ -90,107 +24,8 @@ * * It relies on MIBreakpoints for the actual back-end interface. */ -public class MIBreakpointsManager extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener +public class MIBreakpointsManager extends BreakpointsMediator { - // Note: Find a way to import this (careful of circular dependencies) - public final static String GDB_DEBUG_MODEL_ID = "org.eclipse.cdt.dsf.gdb"; //$NON-NLS-1$ - - // Extra breakpoint attributes - private static final String ATTR_DEBUGGER_PATH = GdbPlugin.PLUGIN_ID + ".debuggerPath"; //$NON-NLS-1$ - private static final String ATTR_THREAD_FILTER = GdbPlugin.PLUGIN_ID + ".threadFilter"; //$NON-NLS-1$ - private static final String ATTR_THREAD_ID = GdbPlugin.PLUGIN_ID + ".threadID"; //$NON-NLS-1$ - - // Services - ICommandControl fConnection; - IRunControl fRunControl; - ISourceLookup fSourceLookup; - IBreakpoints fBreakpoints; - IBreakpointManager fBreakpointManager; // Platform breakpoint manager (not this!) - BreakpointActionManager fBreakpointActionManager; - - /////////////////////////////////////////////////////////////////////////// - // Breakpoints tracking - /////////////////////////////////////////////////////////////////////////// - - private String fDebugModelId; - - // Holds the set of platform breakpoints with their corresponding back-end - // breakpoint attributes, per context (i.e. each platform breakpoint is - // replicated for each execution context). - // - Context entry added/removed on start/stopTrackingBreakpoints() - // - Augmented on breakpointAdded() - // - Modified on breakpointChanged() - // - Diminished on breakpointRemoved() - private Map>> fPlatformBPs = - new HashMap>>(); - - // Holds the set of target breakpoints, per execution context, and their - // mapping to the corresponding platform breakpoint. In a given execution - // context there can only be one platform breakpoint per target breakpoint. - // Acts as a mapping from target (low-level) BP to the corresponding platform - // (high-level) BP. - // Updated when: - // - We start/stop tracking an execution context - // - A platform breakpoint is added/removed - // - A thread filter is applied/removed - private Map> fTargetBPs = - new HashMap>(); - - // Holds the mapping from platform breakpoint to the corresponding target - // breakpoint(s), per context. There can be multiple back-end BPs for a - // single platform BP in the case of [1] multiple target contexts, and/or - // [2] thread filtering. - // Updated when: - // - We start/stop tracking an execution context - // - A platform breakpoint is added/removed - // - A thread filter is applied/removed - private Map>> fBreakpointIDs = - new HashMap>>(); - - // Holds the mapping from platform breakpoint to the corresponding target - // breakpoint threads, per context. - // Updated when: - // - We start/stop tracking an execution context - // - A platform breakpoint is added/removed - // - A thread filter is applied/removed - private Map>> fBreakpointThreads = - new HashMap>>(); - - // Due to the very asynchronous nature of DSF, a new breakpoint request can - // pop up at any time before an ongoing one is completed. The following set - // is used to store requests until the ongoing operation completes. - private Set fPendingRequests = new HashSet(); - private Set fPendingBreakpoints = new HashSet(); - - private Map fBreakpointMarkerProblems = - new HashMap(); - - /////////////////////////////////////////////////////////////////////////// - // String constants - /////////////////////////////////////////////////////////////////////////// - - private static final String NULL_STRING = ""; //$NON-NLS-1$ - - static final String CONTEXT_ALREADY_INITIALIZED = "Context already initialized"; //$NON-NLS-1$ - static final String INVALID_CONTEXT_TYPE = "Invalid context type"; //$NON-NLS-1$ - static final String INVALID_CONTEXT = "Invalid context"; //$NON-NLS-1$ - - static final String UNABLE_TO_READ_BREAKPOINT = "Unable to read initial breakpoint attributes"; //$NON-NLS-1$ - static final String BREAKPOINT_NOT_INSTALLED = "Breakpoints not installed for given context"; //$NON-NLS-1$ - static final String BREAKPOINT_ALREADY_INSTALLED = "Breakpoint already installed"; //$NON-NLS-1$ - static final String BREAKPOINT_ALREADY_REMOVED = "Breakpoint already removed"; //$NON-NLS-1$ - - static final String INVALID_BREAKPOINT = "Invalid breakpoint"; //$NON-NLS-1$ - static final String UNKNOWN_BREAKPOINT = "Unknown breakpoint"; //$NON-NLS-1$ - static final String INVALID_PARAMETER = "Invalid breakpoint parameter(s)"; //$NON-NLS-1$ - - static final String NO_DEBUGGER_PATH = "No debugger path for breakpoint"; //$NON-NLS-1$ - static final String NO_MARKER_FOR_BREAKPOINT = "No marker associated with breakpoint"; //$NON-NLS-1$ - - /////////////////////////////////////////////////////////////////////////// - // AbstractDsfService - /////////////////////////////////////////////////////////////////////////// - /** * The service constructor. * Performs basic instantiation (method initialize() performs the real @@ -200,1515 +35,6 @@ * @param debugModelId the debugging model */ public MIBreakpointsManager(DsfSession session, String debugModelId) { - super(session); - fDebugModelId = debugModelId; - } - - //------------------------------------------------------------------------- - // initialize - //------------------------------------------------------------------------- - // - Collect references for the services we interact with - // - Register to interesting events - // - Obtain the list of platform breakpoints - // - Register the service for interested parties - //------------------------------------------------------------------------- - - /* (non-Javadoc) - * @see org.eclipse.cdt.dsf.service.AbstractDsfService#initialize(org.eclipse.cdt.dsf.concurrent.RequestMonitor) - */ - @Override - public void initialize(final RequestMonitor rm) { - super.initialize( - new RequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - doInitialize(rm); - }}); - } - - /** - * @param rm - */ - private void doInitialize(RequestMonitor rm) { - - // Get the required services references from central repository - fConnection = getServicesTracker().getService(ICommandControl.class); - fRunControl = getServicesTracker().getService(IRunControl.class); - fSourceLookup = getServicesTracker().getService(ISourceLookup.class); - fBreakpoints = getServicesTracker().getService(IBreakpoints.class); - fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager(); - fBreakpointActionManager = CDebugCorePlugin.getDefault().getBreakpointActionManager(); - - // Register to the useful events - getSession().addServiceEventListener(this, null); - fBreakpointManager.addBreakpointListener(this); - fBreakpointManager.addBreakpointManagerListener(this); - - // And register this service - register(new String[] { MIBreakpointsManager.class.getName() }, - new Hashtable()); - rm.done(); - } - - //------------------------------------------------------------------------- - // shutdown - //------------------------------------------------------------------------- - // - Un-register the service - // - Stop listening to events - // - Remove the breakpoints installed by this service - // - // Since we are shutting down, there is no overwhelming need - // to keep the maps coherent... - //------------------------------------------------------------------------- - - /* (non-Javadoc) - * @see org.eclipse.cdt.dsf.service.AbstractDsfService#shutdown(org.eclipse.cdt.dsf.concurrent.RequestMonitor) - */ - @Override - public void shutdown(final RequestMonitor rm) { - - // Stop accepting requests and events - unregister(); - getSession().removeServiceEventListener(this); - fBreakpointManager.removeBreakpointListener(this); - fBreakpointManager.removeBreakpointManagerListener(this); - - // Cleanup the breakpoints that are still installed by the service. - // Use a counting monitor which will call mom to complete the shutdown - // after the breakpoints are un-installed (successfully or not). - CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleCompleted() { - MIBreakpointsManager.super.shutdown(rm); - } - }; - - List targetBPKeys = new ArrayList(fTargetBPs.size()); - targetBPKeys.addAll(0, fTargetBPs.keySet()); - for (IBreakpointsTargetDMContext dmc : targetBPKeys) { - stopTrackingBreakpoints(dmc, countingRm); - } - countingRm.setDoneCount(targetBPKeys.size()); - } - - //------------------------------------------------------------------------- - // getBundleContext - //------------------------------------------------------------------------- - - /* (non-Javadoc) - * @see org.eclipse.cdt.dsf.service.AbstractDsfService#getBundleContext() - */ - @Override - protected BundleContext getBundleContext() { - return GdbPlugin.getBundleContext(); - } - - /////////////////////////////////////////////////////////////////////////// - // IBreakpointsManager - /////////////////////////////////////////////////////////////////////////// - - //------------------------------------------------------------------------- - // startTrackingBreakpoints - //------------------------------------------------------------------------- - // - Augment the maps with the new execution context - // - Install the platform breakpoints on the selected target - //------------------------------------------------------------------------- - - /** - * Install and begin tracking breakpoints for given context. The service - * will keep installing new breakpoints that appear in the IDE for this - * context until {@link #uninstallBreakpoints(IDMContext)} is called for that - * context. - * @param dmc Context to start tracking breakpoints for. - * @param rm Completion callback. - */ - public void startTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { - - // Validate the execution context - if (dmc == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_CONTEXT, null)); - rm.done(); - return; - } - - // Make sure a mapping for this execution context does not already exist - Map> platformBPs = fPlatformBPs.get(dmc); - Map> breakpointIDs = fBreakpointIDs.get(dmc); - Map targetIDs = fTargetBPs.get(dmc); - Map> threadIDs = fBreakpointThreads.get(dmc); - if ((platformBPs != null) || (breakpointIDs != null) || (targetIDs != null) || (threadIDs != null)) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, CONTEXT_ALREADY_INITIALIZED, null)); - rm.done(); - return; - } - - // Create entries in the breakpoint tables for the new context. These entries should only - // be removed when this service stops tracking breakpoints for the given context. - fPlatformBPs.put(dmc, new HashMap>()); - fBreakpointIDs.put(dmc, new HashMap>()); - fTargetBPs.put(dmc, new HashMap()); - fBreakpointThreads.put(dmc, new HashMap>()); - - // Install the platform breakpoints (stored in fPlatformBPs) on the target. - new Job("DSF BreakpointsManager: Install initial breakpoints on target") { //$NON-NLS-1$ - @Override - protected IStatus run(IProgressMonitor monitor) { - // Submit the runnable to plant the breakpoints on dispatch thread. - getExecutor().submit(new Runnable() { - public void run() { - installInitialBreakpoints(dmc, rm); - } - }); - - return Status.OK_STATUS; - } - }.schedule(); - } - - /** - * Installs the breakpoints that existed prior to the activation of this - * execution context. - * - * @param dmc - * @param initialPlatformBPs - * @param rm - */ - private void installInitialBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) - { - // Retrieve the set of platform breakpoints for this context - final Map> platformBPs = fPlatformBPs.get(dmc); - if (platformBPs == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); - rm.done(); - return; - } - - // Read current breakpoints from platform and copy their augmented - // attributes into the local reference map - try { - IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(fDebugModelId); - for (IBreakpoint breakpoint : breakpoints) { - if (supportsBreakpoint(breakpoint)) { - @SuppressWarnings("unchecked") - Map attributes = breakpoint.getMarker().getAttributes(); - attributes.put(ATTR_DEBUGGER_PATH, NULL_STRING); - attributes.put(ATTR_THREAD_FILTER, extractThreads(dmc, (ICBreakpoint) breakpoint)); - attributes.put(ATTR_THREAD_ID, NULL_STRING); - platformBPs.put((ICBreakpoint) breakpoint, attributes); - } - } - } catch (CoreException e) { - IStatus status = new Status( - IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNABLE_TO_READ_BREAKPOINT, e); - rm.setStatus(status); - rm.done(); - } - - // Install the individual breakpoints on the dispatcher thread - // Requires a counting monitor to know when we are done - final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm); - countingRm.setDoneCount(platformBPs.size()); - - for (final ICBreakpoint breakpoint : platformBPs.keySet()) { - final Map attributes = platformBPs.get(breakpoint); - // Upon determining the debuggerPath, the breakpoint is installed - determineDebuggerPath(dmc, attributes, new RequestMonitor(getExecutor(), countingRm) { - @Override - protected void handleSuccess() { - // Install only if the breakpoint is enabled at startup (Bug261082) - boolean bpEnabled = attributes.get(ICBreakpoint.ENABLED).equals(true) && fBreakpointManager.isEnabled(); - if (bpEnabled) - installBreakpoint(dmc, breakpoint, attributes, countingRm); - else - countingRm.done(); - } - }); - } - } - - //------------------------------------------------------------------------- - // stopTrackingBreakpoints - //------------------------------------------------------------------------- - // - Remove the target breakpoints for the given execution context - // - Update the maps - //------------------------------------------------------------------------- - - /** - * Uninstall and stop tracking breakpoints for the given context. - * @param dmc Context to start tracking breakpoints for. - * @param rm Completion callback. - */ - public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { - - // Validate the context - if (dmc == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); - rm.done(); - return; - } - - // Retrieve the set of platform breakpoints for this context - final Map> platformBPs = fPlatformBPs.get(dmc); - if (platformBPs == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); - rm.done(); - return; - } - - // Un-install the individual breakpoints on the dispatcher thread - // (requires a counting monitor to know when we are done). - // On completion (success or failure), update the maps. - final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleCompleted() { - fPlatformBPs.remove(dmc); - fBreakpointIDs.remove(dmc); - fTargetBPs.remove(dmc); - fBreakpointThreads.remove(dmc); - rm.done(); - } - }; - countingRm.setDoneCount(platformBPs.size()); - - for (final ICBreakpoint breakpoint : platformBPs.keySet()) { - uninstallBreakpoint(dmc, breakpoint, - new RequestMonitor(getExecutor(), countingRm) { - @Override - protected void handleCompleted() { - countingRm.done(); - } - }); - } - } - - /////////////////////////////////////////////////////////////////////////// - // Back-end interface functions - /////////////////////////////////////////////////////////////////////////// - - //------------------------------------------------------------------------- - // installBreakpoint - //------------------------------------------------------------------------- - - /** - * Install a platform breakpoint on the back-end. For a given context, a - * platform breakpoint can resolve into multiple back-end breakpoints when - * threads are taken into account. - * - * @param dmc - * @param breakpoint - * @param attributes - * @param rm - */ - private void installBreakpoint(IBreakpointsTargetDMContext dmc, final ICBreakpoint breakpoint, - final Map attributes, final RequestMonitor rm) - { - // Retrieve the breakpoint maps - final Map> platformBPs = fPlatformBPs.get(dmc); - assert platformBPs != null; - - final Map> breakpointIDs = fBreakpointIDs.get(dmc); - assert breakpointIDs != null; - - final Map targetBPs = fTargetBPs.get(dmc); - assert targetBPs != null; - - final Map> threadsIDs = fBreakpointThreads.get(dmc); - assert threadsIDs != null; - - // Minimal validation - if (breakpointIDs.containsKey(breakpoint) || targetBPs.containsValue(breakpoint)) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, BREAKPOINT_ALREADY_INSTALLED, null)); - rm.done(); - return; - } - - // Ensure the breakpoint has a valid debugger source path - if (breakpoint instanceof ICLineBreakpoint && !(breakpoint instanceof ICAddressBreakpoint)) { - String debuggerPath = (String) attributes.get(ATTR_DEBUGGER_PATH); - if (debuggerPath == null || debuggerPath == NULL_STRING) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, NO_DEBUGGER_PATH, null)); - rm.done(); - return; - } - } - - // A back-end breakpoint needs to be installed for each specified thread - // Note: This is a bit academic since [1] thread info is not kept by the - // BreakpointManager (so it can not possibly be restored when a target is - // started), and [2] the standard GUI doesn't allow to specify thread at - // breakpoint creation. However, it is conceivable that an enhanced Editor - // would permit it. - final Set threads = getThreads(attributes); - - // Update the breakpoint state when all back-end breakpoints have been installed - final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleCompleted() { - // Store the platform breakpoint - platformBPs.put(breakpoint, attributes); - rm.done(); - } - }; - installRM.setDoneCount(threads.size()); - - // Install the back-end breakpoint(s) - for (final String thread : threads) { - DataRequestMonitor drm = - new DataRequestMonitor(getExecutor(), installRM) { - @Override - protected void handleSuccess() { - // Add the new back-end breakpoint to the map - Vector list = breakpointIDs.get(breakpoint); - if (list == null) - list = new Vector(); - IBreakpointDMContext targetBP = getData(); - list.add(targetBP); - breakpointIDs.put(breakpoint, list); - - // Add the reverse mapping - targetBPs.put(targetBP, breakpoint); - - // And update the corresponding thread list - Set thrds = threadsIDs.get(breakpoint); - if (thrds == null) - thrds = new HashSet(); - thrds.add(thread); - threadsIDs.put(breakpoint, thrds); - - // Reset the thread (is it necessary?) - attributes.put(ATTR_THREAD_ID, NULL_STRING); - - // Remove breakpoint problem marker (if any) - removeBreakpointProblemMarker(breakpoint); - - // Finally, update the platform breakpoint - try { - breakpoint.incrementInstallCount(); - } catch (CoreException e) { - } - installRM.done(); - } - - @Override - protected void handleError() { - addBreakpointProblemMarker(breakpoint, "Breakpoint attribute problem: installation failed", IMarker.SEVERITY_WARNING); //$NON-NLS-1$ - installRM.done(); - } - }; - - // Convert the breakpoint attributes for the back-end - attributes.put(ATTR_THREAD_ID, thread); - Map targetAttributes = convertToTargetBreakpoint(breakpoint, attributes); - fBreakpoints.insertBreakpoint(dmc, targetAttributes, drm); - } - } - - private void addBreakpointProblemMarker(final ICBreakpoint breakpoint, final String description, final int severity) { - - new Job("Add Breakpoint Problem Marker") { //$NON-NLS-1$ - @Override - protected IStatus run(IProgressMonitor monitor) { - - if (breakpoint instanceof ICLineBreakpoint) { - // If we have already have a problem marker on this breakpoint - // we should remove it first. - IMarker marker = fBreakpointMarkerProblems.remove(breakpoint); - if (marker != null) { - try { - marker.delete(); - } catch (CoreException e) { - } - } - - ICLineBreakpoint lineBreakpoint = (ICLineBreakpoint) breakpoint; - try { - // Locate the workspace resource via the breakpoint marker - IMarker breakpoint_marker = lineBreakpoint.getMarker(); - IResource resource = breakpoint_marker.getResource(); - - // Add a problem marker to the resource - IMarker problem_marker = resource.createMarker(BreakpointProblems.BREAKPOINT_PROBLEM_MARKER_ID); - int line_number = lineBreakpoint.getLineNumber(); - problem_marker.setAttribute(IMarker.LOCATION, String.valueOf(line_number)); - problem_marker.setAttribute(IMarker.MESSAGE, description); - problem_marker.setAttribute(IMarker.SEVERITY, severity); - problem_marker.setAttribute(IMarker.LINE_NUMBER, line_number); - - // And save the baby - fBreakpointMarkerProblems.put(breakpoint, problem_marker); - } catch (CoreException e) { - } - } - return Status.OK_STATUS; - } - }.schedule(); - } - - private void removeBreakpointProblemMarker(final ICBreakpoint breakpoint) { - - new Job("Remove Breakpoint Problem Marker") { //$NON-NLS-1$ - @Override - protected IStatus run(IProgressMonitor monitor) { - - IMarker marker = fBreakpointMarkerProblems.remove(breakpoint); - if (marker != null) { - try { - marker.delete(); - } catch (CoreException e) { - } - } - - return Status.OK_STATUS; - } - }.schedule(); - } - - //------------------------------------------------------------------------- - // uninstallBreakpoint - //------------------------------------------------------------------------- - - /** - * Un-install an individual breakpoint on the back-end. For one platform - * breakpoint in a given execution context, there could be multiple - * corresponding back-end breakpoints (one per thread). - * - * @param dmc - * @param breakpoint - * @param rm - */ - private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, - final ICBreakpoint breakpoint, final RequestMonitor rm) - { - // Retrieve the breakpoint maps - final Map> platformBPs = fPlatformBPs.get(dmc); - assert platformBPs != null; - - final Map> breakpointIDs = fBreakpointIDs.get(dmc); - assert breakpointIDs != null; - - final Map targetBPs = fTargetBPs.get(dmc); - assert targetBPs != null; - - final Map> threadsIDs = fBreakpointThreads.get(dmc); - assert threadsIDs != null; - - // Remove breakpoint problem marker (if any) - removeBreakpointProblemMarker(breakpoint); - - // Minimal validation - if (!platformBPs.containsKey(breakpoint) || !breakpointIDs.containsKey(breakpoint) || !targetBPs.containsValue(breakpoint)) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, BREAKPOINT_ALREADY_REMOVED, null)); - rm.done(); - return; - } - - // Remove completion monitor - // Upon completion, update the mappings - CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - // Update the mappings - platformBPs.remove(breakpoint); - threadsIDs.remove(breakpoint); - - Vector contexts = breakpointIDs.get(breakpoint); - if (contexts != null) { - for (IBreakpointDMContext context : contexts) - targetBPs.remove(context); - } - - breakpointIDs.get(breakpoint).clear(); - breakpointIDs.remove(breakpoint); - - fPendingRequests.remove(breakpoint); - - rm.done(); - } - }; - - // Remove the back-end breakpoints - Vector list = breakpointIDs.get(breakpoint); - int count = 0; - if (list != null) { - for (IBreakpointDMContext bp : list) { - fBreakpoints.removeBreakpoint(bp, removeRM); - try { - breakpoint.decrementInstallCount(); - } catch (CoreException e) { - } - } - count = list.size(); - } - removeRM.setDoneCount(count); - } - - //------------------------------------------------------------------------- - // modifyBreakpoint - //------------------------------------------------------------------------- - - /** - * Modify a platform breakpoint which can translate to quite a few updates - * on the target... - * - * @param dmc - * @param breakpoint - * @param attributes - * @param oldValues - * @param rm - */ - private void modifyBreakpoint(final IBreakpointsTargetDMContext dmc, final ICBreakpoint breakpoint, - final Map attributes, final IMarkerDelta oldValues, final RequestMonitor rm) - { - // Retrieve the breakpoint maps - final Map> platformBPs = fPlatformBPs.get(dmc); - assert platformBPs != null; - - final Map> breakpointIDs = fBreakpointIDs.get(dmc); - assert breakpointIDs != null; - - final Map targetBPs = fTargetBPs.get(dmc); - assert targetBPs != null; - - final Map> threadsIDs = fBreakpointThreads.get(dmc); - assert threadsIDs != null; - - // Minimal validation - if (!platformBPs.containsKey(breakpoint)) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, UNKNOWN_BREAKPOINT, null)); - rm.done(); - return; - } - - // Check if the breakpoint is installed: it might not have been if it wasn't enabled at startup (Bug261082) - // Or the installation might have failed; in this case, we still try to install it again because - // some attribute might have changed which will make the install succeed. - if (!breakpointIDs.containsKey(breakpoint) && !targetBPs.containsValue(breakpoint)) { - // Install only if the breakpoint is enabled - boolean bpEnabled = attributes.get(ICBreakpoint.ENABLED).equals(true) && fBreakpointManager.isEnabled(); - if (bpEnabled) { - attributes.put(ATTR_DEBUGGER_PATH, NULL_STRING); - attributes.put(ATTR_THREAD_FILTER, extractThreads(dmc, breakpoint)); - attributes.put(ATTR_THREAD_ID, NULL_STRING); - determineDebuggerPath(dmc, attributes, new RequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - installBreakpoint(dmc, breakpoint, attributes, rm); - } - }); - } - else { - rm.done(); - } - return; - } - - // Get the original breakpoint attributes - final Map original_attributes = platformBPs.get(breakpoint); - if (original_attributes == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, INVALID_BREAKPOINT, null)); - rm.done(); - return; - } - - // Determine the attributes delta - final Map oldAttributes = new HashMap(original_attributes); - oldAttributes.put(ATTR_THREAD_FILTER, threadsIDs.get(breakpoint)); - - final Set newThreads = extractThreads(dmc, breakpoint); - Map newAttributes = new HashMap(attributes); - newAttributes.put(ATTR_THREAD_FILTER, newThreads); - - final Map attributesDelta = determineAttributesDelta(oldAttributes, newAttributes); - - // Get the list of back-end breakpoints - final Vector oldTargetBPs = new Vector(breakpointIDs.get(breakpoint)); - if (oldTargetBPs == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, INVALID_BREAKPOINT, null)); - rm.done(); - return; - } - - // We're all set for the breakpoint update. - // - // The path for a simple update is straightforward: - // - For each back-end BP corresponding to a platform BP - // - Send an update command to the back-end - // - If the operation succeeded, update the data structures - // - If the operation failed, try to roll-back - // - // In cases where the the back-end breakpoint cannot be - // simply updated (e.g. thread filter modification), the old - // breakpoint has to be removed and new one(s) inserted. - // - // The path for such an update is: - // - Install the updated breakpoint - // - In the operation succeeded - // - Remove the old breakpoint(s) - // - Perform any pending update - - // Update completion monitor - final CountingRequestMonitor updateRM = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - // Success: simply store the new attributes - platformBPs.put(breakpoint, attributes); - rm.done(); - } - - @Override - protected void handleError() { - // Reset the breakpoint attributes. This will trigger a - // breakpoint change event and the correct delta will be - // computed, resulting in a correctly restored breakpoint - // at the back-end. - rollbackAttributes(breakpoint, oldValues); - platformBPs.put(breakpoint, attributes); - - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); - rm.done(); - } - }; - - // Everything OK: remove the old back-end breakpoints - final Vector newTargetBPs = new Vector(); - final CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - // All right! Save the new list and perform the final update - Map> breakpointIDs = fBreakpointIDs.get(dmc); - if (breakpointIDs == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_BREAKPOINT, null)); - rm.done(); - return; - } - breakpointIDs.put(breakpoint, newTargetBPs); - for (IBreakpointDMContext ref : newTargetBPs) { - fBreakpoints.updateBreakpoint(ref, attributesDelta, updateRM); - } - updateRM.setDoneCount(newTargetBPs.size()); - }}; - - // New back-end breakpoints insertion monitor - // Holds the list of new back-end breakpoint contexts of the platform breakpoint - final DataRequestMonitor> insertRM = - new DataRequestMonitor>(getExecutor(), null) { - - @Override - // In theory, we could have had a partial success and the original threads - // list would be invalid. We think it is highly unlikely so we assume that - // either everything went fine or else everything failed. - protected void handleSuccess() { - // Get the list of new back-end breakpoints contexts - newTargetBPs.addAll(getData()); - threadsIDs.put(breakpoint, newThreads); - for (IBreakpointDMContext ref : oldTargetBPs) { - fBreakpoints.removeBreakpoint(ref, removeRM); - try { - breakpoint.decrementInstallCount(); // A tad early but it should work... - } catch (CoreException e) { - } - } - removeRM.setDoneCount(oldTargetBPs.size()); - } - - @Override - protected void handleError() { - // Keep the old threads list and reset the attributes - // (bad attributes are the likely cause of failure) - updateRM.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); - updateRM.setDoneCount(0); - } - }; - - // If the changes in the breakpoint attributes justify it, install a - // new set of back-end breakpoint(s) and then update them - if (needsResinstallation(attributesDelta)) { - reinstallBreakpoint(dmc, breakpoint, attributes, newThreads, insertRM); - } - else { - // Update the back-end breakpoint(s) state - for (IBreakpointDMContext ref : oldTargetBPs) { - fBreakpoints.updateBreakpoint(ref, attributesDelta, updateRM); - } - updateRM.setDoneCount(oldTargetBPs.size()); - } + super(session, new MIBreakpointAttributeTranslator(session, debugModelId)); } - - /** - * Re-install the back-end breakpoints - * - * @param context the target context - * @param breakpoint the platform breakpoint - * @param attributes breakpoint augmented attributes - * @param threads list of threads where breakpoint is to be installed - * @param drm will contain the list of successfully installed back-end breakpoints - */ - private void reinstallBreakpoint(final IBreakpointsTargetDMContext context, final ICBreakpoint breakpoint, - final Map attributes, Set threads, final DataRequestMonitor> drm) - { - // Our new list of back-end breakpoints. Built as we go. - final Vector breakpointList = new Vector(); - - // Counting monitor for the new back-end breakpoints to install - // Once we're done, return the new list of back-end breakpoints contexts - final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), drm) { - @Override - protected void handleSuccess() { - // Report whatever we have managed to install - // It is very likely installation either succeeded or failed for all - drm.setData(breakpointList); - drm.done(); - } - }; - installRM.setDoneCount(threads.size()); - - // And install the new back-end breakpoints - for (String thread : threads) { - // Convert the breakpoint attributes for the back-end - // Refresh the set of attributes at each iteration just in case... - Map attrs = convertToTargetBreakpoint(breakpoint, attributes); - if (!fBreakpointManager.isEnabled()) { - attrs.put(MIBreakpoints.IS_ENABLED, false); - } - // Add the secret ingredient.. - attrs.put(MIBreakpointDMData.THREAD_ID, thread); - - // Then install the spiked breakpoint - fBreakpoints.insertBreakpoint(context, attrs, - new DataRequestMonitor(getExecutor(), installRM) { - @Override - protected void handleSuccess() { - // Add the new back-end breakpoint context to the list - breakpointList.add(getData()); - try { - breakpoint.incrementInstallCount(); - } catch (CoreException e) { - } - installRM.done(); - } - - @Override - protected void handleError() { - // Add the new back-end breakpoint context to the list - installRM.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); - installRM.done(); - } - }); - } - } - - /////////////////////////////////////////////////////////////////////////// - // IBreakpointManagerListener implementation - /////////////////////////////////////////////////////////////////////////// - - /* (non-Javadoc) - * @see org.eclipse.debug.core.IBreakpointManagerListener#breakpointManagerEnablementChanged(boolean) - */ - public void breakpointManagerEnablementChanged(boolean enabled) { - - // Only modify enabled breakpoints - for (IBreakpointsTargetDMContext context : fBreakpointIDs.keySet()) { - for (ICBreakpoint breakpoint : fBreakpointIDs.get(context).keySet()) { - try { - if (breakpoint.isEnabled()) { - for (IBreakpointDMContext ref : fBreakpointIDs.get(context).get(breakpoint)) { - Map delta = new HashMap(); - delta.put(MIBreakpoints.IS_ENABLED, enabled); - fBreakpoints.updateBreakpoint(ref, delta, new RequestMonitor(getExecutor(), null)); - } - } - } catch (CoreException e) { - } - } - } - } - - /////////////////////////////////////////////////////////////////////////// - // IBreakpointListener implementation - /////////////////////////////////////////////////////////////////////////// - - /* (non-Javadoc) - * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint) - */ - @ThreadSafe - public void breakpointAdded(final IBreakpoint breakpoint) { - - if (supportsBreakpoint(breakpoint)) { - try { - // Retrieve the breakpoint attributes - @SuppressWarnings("unchecked") - final Map attrs = breakpoint.getMarker().getAttributes(); - - getExecutor().execute(new DsfRunnable() { - public void run() { - final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { - @Override - protected void handleError() { - if (getStatus().getSeverity() == IStatus.ERROR) { - GdbPlugin.getDefault().getLog().log(getStatus()); - } - } - }; - countingRm.setDoneCount(fPlatformBPs.size()); - - // Install the breakpoint in all the execution contexts - for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { - determineDebuggerPath(dmc, attrs, - new RequestMonitor(getExecutor(), countingRm) { - @Override - protected void handleSuccess() { - installBreakpoint(dmc, (ICBreakpoint) breakpoint, - attrs, countingRm); - } - }); - } - } - }); - } catch (CoreException e) { - } catch (RejectedExecutionException e) { - } - } - } - - /** - * @param bp - * @return - * @throws CoreException - */ - private IDsfBreakpointExtension getFilterExtension(ICBreakpoint bp) throws CoreException { - return (IDsfBreakpointExtension) bp.getExtension(GDB_DEBUG_MODEL_ID, ICBreakpointExtension.class); - } - - /* (non-Javadoc) - * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) - */ - public void breakpointChanged(final IBreakpoint breakpoint, final IMarkerDelta delta) { - - if (supportsBreakpoint(breakpoint)) { - - try { - // Retrieve the breakpoint attributes - @SuppressWarnings("unchecked") - final Map attrs = breakpoint.getMarker().getAttributes(); - if (!fBreakpointManager.isEnabled()) { - attrs.put(ICBreakpoint.ENABLED, false); - } - - // Modify the breakpoint in all the target contexts - getExecutor().execute( new DsfRunnable() { - public void run() { - - // If the breakpoint is currently being updated, queue the request and exit - if (fPendingRequests.contains(breakpoint)) { - fPendingBreakpoints.add(breakpoint); - return; - } - - // Keep track of the updates - final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { - @Override - protected void handleCompleted() { - - if (!isSuccess()) { - if (getStatus().getSeverity() == IStatus.ERROR) { - GdbPlugin.getDefault().getLog().log(getStatus()); - } - } - - // Indicate that the pending request has completed - fPendingRequests.remove(breakpoint); - - // Process the next pending update for this breakpoint - if (fPendingBreakpoints.contains(breakpoint)) { - fPendingBreakpoints.remove(breakpoint); - breakpointChanged(breakpoint, delta); - } - } - }; - countingRm.setDoneCount(fPlatformBPs.size()); - - // Mark the breakpoint as being updated and go - fPendingRequests.add(breakpoint); - - // Modify the breakpoint in all the execution contexts - for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { - determineDebuggerPath(dmc, attrs, - new RequestMonitor(getExecutor(), countingRm) { - @Override - protected void handleSuccess() { - modifyBreakpoint(dmc, (ICBreakpoint) breakpoint, attrs, delta, new RequestMonitor(getExecutor(), countingRm)); - } - }); - } - } - }); - } catch (CoreException e) { - } catch (RejectedExecutionException e) { - } - } - } - - /* (non-Javadoc) - * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) - */ - public void breakpointRemoved(final IBreakpoint breakpoint, IMarkerDelta delta) { - - if (supportsBreakpoint(breakpoint)) { - try { - getExecutor().execute(new DsfRunnable() { - public void run() { - CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { - @Override - protected void handleError() { - if (getStatus().getSeverity() == IStatus.ERROR) { - GdbPlugin.getDefault().getLog().log(getStatus()); - } - } - }; - countingRm.setDoneCount(fPlatformBPs.size()); - - // Remove the breakpoint in all the execution contexts - for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { - if (fPlatformBPs.get(dmc).containsKey(breakpoint)) { - uninstallBreakpoint(dmc, (ICBreakpoint) breakpoint, countingRm); - } - } - } - }); - } catch (RejectedExecutionException e) { - } - } - } - - /////////////////////////////////////////////////////////////////////////// - // IServiceEventListener - /////////////////////////////////////////////////////////////////////////// - - //------------------------------------------------------------------------- - // Breakpoints - //------------------------------------------------------------------------- - - @DsfServiceEventHandler - public void eventDispatched(BreakpointAddedEvent e) { - // Nothing to do - already handled by breakpointAdded() - } - - @DsfServiceEventHandler - public void eventDispatched(BreakpointUpdatedEvent e) { - // Nothing to do - already handled by breakpointChanged() - } - - @DsfServiceEventHandler - public void eventDispatched(BreakpointRemovedEvent e) { - // Nothing to do - already handled by breakpointRemoved() - } - - /* - * When a watchpoint goes out of scope, it is automatically removed from - * the back-end. To keep our internal state synchronized, we have to - * remove it from our breakpoints maps. - * Unfortunately, GDB doesn't generate the correct event... - */ - @DsfServiceEventHandler - public void eventDispatched(MIWatchpointScopeEvent e) { - } - - //------------------------------------------------------------------------- - // Breakpoint actions - //------------------------------------------------------------------------- - - @DsfServiceEventHandler - public void eventDispatched(SuspendedEvent e) { - - if (e.getMIEvent() instanceof MIBreakpointHitEvent) { - MIBreakpointHitEvent evt = (MIBreakpointHitEvent) e.getMIEvent(); - performBreakpointAction(evt.getDMContext(), evt.getNumber()); - return; - } - - if (e.getMIEvent() instanceof MIWatchpointTriggerEvent) { - MIWatchpointTriggerEvent evt = (MIWatchpointTriggerEvent) e.getMIEvent(); - performBreakpointAction(evt.getDMContext(), evt.getNumber()); - return; - } - } - - private void performBreakpointAction(final IDMContext context, int number) { - // Identify the platform breakpoint - final ICBreakpoint breakpoint = findPlatformBreakpoint(number); - - // Perform the actions asynchronously (otherwise we can have a deadlock...) - new Job("Breakpoint action") { //$NON-NLS-1$ - { setSystem(true); } - @Override - protected IStatus run(IProgressMonitor monitor) { - fBreakpointActionManager.executeActions(breakpoint, new BreakpointActionAdapter(getExecutor(), getServicesTracker(), context)); - return Status.OK_STATUS; - }; - }.schedule(); - } - - // Helper function to locate the platform breakpoint corresponding - // to the target breakpoint/watchpoint that was just hit - - // FIXME: (Bug228703) Need a way to identify the correct context where the BP was hit - private ICBreakpoint findPlatformBreakpoint(int targetBreakpointID) { - Set targets = fTargetBPs.keySet(); - for (IBreakpointsTargetDMContext target : targets) { - Map bps = fTargetBPs.get(target); - Set contexts = bps.keySet(); - for (IBreakpointDMContext context : contexts) { - if (context instanceof MIBreakpointDMContext) { - MIBreakpointDMContext ctx = (MIBreakpointDMContext) context; - if (ctx.getReference() == targetBreakpointID) { - return bps.get(context); - } - } - } - } - return null; - } - - //------------------------------------------------------------------------- - // Session exit - //------------------------------------------------------------------------- - - /** - * @since 1.1 - * @nooverride This method is not intended to be re-implemented or extended by clients. - * @noreference This method is not intended to be referenced by clients. - */ - @DsfServiceEventHandler - public void eventDispatched(ICommandControlShutdownDMEvent e) { - terminated(); - } - - private void terminated() { - // Reset the breakpoint install count - for (IBreakpointsTargetDMContext ctx : fPlatformBPs.keySet()) { - Map> breakpoints = fPlatformBPs.get(ctx); - clearBreakpointStatus(breakpoints.keySet().toArray(new ICBreakpoint[breakpoints.size()]), ctx); - } - // This will prevent Shutdown() from trying to remove bps from a - // backend that has already shutdown - fPlatformBPs.clear(); - } - - /////////////////////////////////////////////////////////////////////////// - // Breakpoint status handling functions - /////////////////////////////////////////////////////////////////////////// - - /** - * @param bps - */ - private void clearBreakpointStatus(final ICBreakpoint[] bps, final IBreakpointsTargetDMContext ctx) - { - new Job("Clear Breakpoints Status") { //$NON-NLS-1$ - @Override - protected IStatus run(IProgressMonitor monitor) { - IWorkspaceRunnable wr = new IWorkspaceRunnable() { - public void run(IProgressMonitor monitor) throws CoreException { - // For every platform breakpoint that has at least one target breakpoint installed - // we must decrement the install count, for every target breakpoint. - // Note that we cannot simply call resetInstallCount() because another - // launch may be using the same platform breakpoint. - Map> breakpoints = fBreakpointIDs.get(ctx); - for (ICBreakpoint breakpoint : breakpoints.keySet()) { - Vector targetBps = breakpoints.get(breakpoint); - for (int i=0; i markerRules = new ArrayList(); - for (ICBreakpoint bp : bps) { - IMarker marker = bp.getMarker(); - if (marker != null) { - ISchedulingRule markerRule = - ResourcesPlugin.getWorkspace().getRuleFactory().markerRule( - marker.getResource()); - if (markerRule == null) { - markerRules = null; - break; - } else { - markerRules.add(markerRule); - } - } - } - if (markerRules != null) { - rule = MultiRule.combine(markerRules.toArray(new ISchedulingRule[markerRules.size()])); - } - - try { - ResourcesPlugin.getWorkspace().run(wr, rule, 0, null); - } catch (CoreException e) { - return e.getStatus(); - } - return Status.OK_STATUS; - } - }.schedule(); - } - - /////////////////////////////////////////////////////////////////////////// - // Support functions - /////////////////////////////////////////////////////////////////////////// - - /** - * supportsBreakpoint - * - * Indicates if it is breakpoint we can deal with. For now, it boils down - * to a CDI breakpoint... - * - * @param bp - * @return - */ - private boolean supportsBreakpoint(IBreakpoint bp) { - if (bp instanceof ICBreakpoint && bp.getModelIdentifier().equals(fDebugModelId)) { - IMarker marker = bp.getMarker(); - if (marker != null) { - return true; - } - } - return false; - } - - /** - * determineDebuggerPath - * - * Adds the path to the source file to the set of attributes - * (for the debugger). - * - * @param dmc - * @param attributes - * @param rm - */ - private void determineDebuggerPath(IBreakpointsTargetDMContext dmc, - final Map attributes, final RequestMonitor rm) - { - String hostPath = (String) attributes.get(ICBreakpoint.SOURCE_HANDLE); - - if (hostPath != null) { - - ISourceLookupDMContext srcDmc = DMContexts.getAncestorOfType(dmc, ISourceLookupDMContext.class); - if (srcDmc != null) { - fSourceLookup.getDebuggerPath(srcDmc, hostPath, - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - attributes.put(ATTR_DEBUGGER_PATH, adjustDebuggerPath(getData())); - rm.done(); - } - }); - } else { - // Source lookup not available for given context, use the host - // path for the debugger path. - attributes.put(ATTR_DEBUGGER_PATH, adjustDebuggerPath(hostPath)); - rm.done(); - } - } else { - // Some types of breakpoints do not require a path - // (e.g. watchpoints) - rm.done(); - } - } - - /** - * See bug232415 - * - * @param path the absolute path to the source file - * @return - */ - private String adjustDebuggerPath(String path) { - String result = path; - // Make it MinGW-specific - if (Platform.getOS().startsWith("win")) { //$NON-NLS-1$ - if (!path.startsWith("/")) { //$NON-NLS-1$ - result = path.substring(path.lastIndexOf('\\') + 1); - } - } - return result; - } - - /** - * Determine the set of modified attributes. - * Elementary set operations in full action :-) - * - * @param oldAttributes - * @param newAttributes - * @return - */ - private Map determineAttributesDelta(Map oldAttributes, Map newAttributes) { - - Map delta = new HashMap(); - - Set oldKeySet = oldAttributes.keySet(); - Set newKeySet = newAttributes.keySet(); - - Set commonKeys = new HashSet(newKeySet); commonKeys.retainAll(oldKeySet); - Set addedKeys = new HashSet(newKeySet); addedKeys.removeAll(oldKeySet); - Set removedKeys = new HashSet(oldKeySet); removedKeys.removeAll(newKeySet); - - // Add the modified attributes - for (String key : commonKeys) { - if (!(oldAttributes.get(key).equals(newAttributes.get(key)))) - delta.put(key, newAttributes.get(key)); - } - - // Add the new attributes - for (String key : addedKeys) { - delta.put(key, newAttributes.get(key)); - } - - // Remove the deleted attributes - for (String key : removedKeys) { - delta.put(key, null); - } - - return convertedAttributes(delta); - } - - /** - * Converts ICBreakpoint attributes to IBreakpoints attributes. - * - * @param cdt_attributes - * @return - */ - private Map convertedAttributes(Map cdt_attributes) { - - Map result = new HashMap(); - - // IBreakpoint attributes - if (cdt_attributes.containsKey(ATTR_DEBUGGER_PATH)) - result.put(MIBreakpoints.FILE_NAME, cdt_attributes.get(ATTR_DEBUGGER_PATH)); - - if (cdt_attributes.containsKey(IMarker.LINE_NUMBER)) - result.put(MIBreakpoints.LINE_NUMBER, cdt_attributes.get(IMarker.LINE_NUMBER)); - - // ICLineBreakpoint attributes - if (cdt_attributes.containsKey(ICLineBreakpoint.FUNCTION)) - result.put(MIBreakpoints.FUNCTION, cdt_attributes.get(ICLineBreakpoint.FUNCTION)); - - if (cdt_attributes.containsKey(ICLineBreakpoint.ADDRESS)) - result.put(MIBreakpoints.ADDRESS, cdt_attributes.get(ICLineBreakpoint.ADDRESS)); - - // ICBreakpoint attributes - if (cdt_attributes.containsKey(ICBreakpoint.CONDITION)) - result.put(MIBreakpoints.CONDITION, cdt_attributes.get(ICBreakpoint.CONDITION)); - - if (cdt_attributes.containsKey(ICBreakpoint.IGNORE_COUNT)) - result.put(MIBreakpoints.IGNORE_COUNT, cdt_attributes.get(ICBreakpoint.IGNORE_COUNT)); - - if (cdt_attributes.containsKey(ICBreakpoint.ENABLED)) - result.put(MIBreakpoints.IS_ENABLED, cdt_attributes.get(ICBreakpoint.ENABLED)); - - // ICWatchpoint attributes - if (cdt_attributes.containsKey(ICWatchpoint.EXPRESSION)) - result.put(MIBreakpoints.EXPRESSION, cdt_attributes.get(ICWatchpoint.EXPRESSION)); - - if (cdt_attributes.containsKey(ICWatchpoint.READ)) - result.put(MIBreakpoints.READ, cdt_attributes.get(ICWatchpoint.READ)); - - if (cdt_attributes.containsKey(ICWatchpoint.WRITE)) - result.put(MIBreakpoints.WRITE, cdt_attributes.get(ICWatchpoint.WRITE)); - - // Threads - if (cdt_attributes.containsKey(ATTR_THREAD_FILTER)) - result.put(ATTR_THREAD_FILTER, cdt_attributes.get(ATTR_THREAD_FILTER)); - - return result; - } - - /** - * Figure out the corresponding number of back-end breakpoints - * Even though the thread IDs are usually integers, they are - * stored as strings in CBreakpoints. - * - * @param attributes - * @return - */ - @SuppressWarnings("unchecked") - private Set getThreads(Map attributes) { - Set threads = (Set) attributes.get(ATTR_THREAD_FILTER); - if (threads == null) { - threads = new HashSet(); - threads.add("0"); // Thread 0 means all threads //$NON-NLS-1$ - } - return threads; - } - - /** - * Get the list of threads from the platform breakpoint attributes - * - * @param breakpoint - * @return - */ - private Set extractThreads(IBreakpointsTargetDMContext context, ICBreakpoint breakpoint) { - Set results = new HashSet(); - - // Find the ancestor - List threads = new ArrayList(1); - - try { - // Retrieve the targets - IDsfBreakpointExtension filterExtension = getFilterExtension(breakpoint); - IContainerDMContext[] targets = filterExtension.getTargetFilters(); - - // If no target is present, breakpoint applies to all. - if (targets.length == 0) { - results.add("0"); //$NON-NLS-1$ - return results; - } - - // Extract the thread IDs (if there is none, we are covered) - for (IContainerDMContext ctxt : targets) { - if (DMContexts.isAncestorOf(ctxt, context)) { - threads.add(filterExtension.getThreadFilters(ctxt)); - } - } - } catch (CoreException e1) { - } - - if (supportsThreads(breakpoint)) { - for (IExecutionDMContext[] targetThreads : threads) { - if (targetThreads != null) { - for (IExecutionDMContext thread : targetThreads) { - if (thread instanceof IMIExecutionDMContext) { - IMIExecutionDMContext dmc = (IMIExecutionDMContext) thread; - results.add(((Integer) dmc.getThreadId()).toString()); - } - } - } else { - results.add("0"); //$NON-NLS-1$ - break; - } - } - } else { - results.add("0"); //$NON-NLS-1$ - } - - return results; - } - - /////////////////////////////////////////////////////////////////////////// - // Non-generic (MI-specific) functions - /////////////////////////////////////////////////////////////////////////// - - /** - * Create a target breakpoint from an ICBreakpoint - * - * @param breakpoint - * @param attributes - * @return - */ - protected Map convertToTargetBreakpoint(ICBreakpoint breakpoint, Map attributes) { - - Map properties = new HashMap(); - - if (breakpoint instanceof ICWatchpoint) { - // Convert the CDI watchpoint to an IBreakpoint - properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.WATCHPOINT); - properties.put(MIBreakpoints.EXPRESSION, attributes.get(ICWatchpoint.EXPRESSION)); - properties.put(MIBreakpoints.READ, attributes.get(ICWatchpoint.READ)); - properties.put(MIBreakpoints.WRITE, attributes.get(ICWatchpoint.WRITE)); - } - else if (breakpoint instanceof ICLineBreakpoint) { - // Convert the CDI breakpoint to an IBreakpoint - properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.BREAKPOINT); - properties.put(MIBreakpoints.FILE_NAME, attributes.get(ATTR_DEBUGGER_PATH)); - properties.put(MIBreakpoints.LINE_NUMBER, attributes.get(IMarker.LINE_NUMBER)); - properties.put(MIBreakpoints.FUNCTION, attributes.get(ICLineBreakpoint.FUNCTION)); - properties.put(MIBreakpoints.ADDRESS, attributes.get(ICLineBreakpoint.ADDRESS)); - } else { - // catchpoint? - } - - // Common fields - properties.put(MIBreakpoints.CONDITION, attributes.get(ICBreakpoint.CONDITION)); - properties.put(MIBreakpoints.IGNORE_COUNT, attributes.get(ICBreakpoint.IGNORE_COUNT)); - properties.put(MIBreakpoints.IS_ENABLED, attributes.get(ICBreakpoint.ENABLED)); - properties.put(MIBreakpointDMData.THREAD_ID, attributes.get(ATTR_THREAD_ID)); - - // Adjust for "skip-all" - if (!fBreakpointManager.isEnabled()) { - properties.put(MIBreakpoints.IS_ENABLED, false); - } - - return properties; - } - - /** - * Determine if the modified attributes necessitate - * a breakpoint removal/re-installation - * - * @param delta - * @return - */ - protected boolean needsResinstallation(Map delta) { - - // Check if there is any modified attribute - if (delta == null) - return false; - - // Check the "critical" attributes - if (delta.containsKey(ATTR_DEBUGGER_PATH) // File name - || delta.containsKey(MIBreakpoints.LINE_NUMBER) // Line number - || delta.containsKey(MIBreakpoints.FUNCTION) // Function name - || delta.containsKey(MIBreakpoints.ADDRESS) // Absolute address - || delta.containsKey(ATTR_THREAD_FILTER) // Thread ID - || delta.containsKey(MIBreakpoints.EXPRESSION) // Watchpoint expression - || delta.containsKey(MIBreakpoints.READ) // Watchpoint type - || delta.containsKey(MIBreakpoints.WRITE)) { // Watchpoint type - return true; - } - - return false; - } - - /** - * @param breakpoint - * @param oldValues - */ - protected void rollbackAttributes(ICBreakpoint breakpoint, IMarkerDelta oldValues) { - - try { - String new_condition = breakpoint.getCondition(); - if (new_condition == null) - new_condition = NULL_STRING; - String old_condition = (oldValues != null) ? oldValues.getAttribute(ICBreakpoint.CONDITION, NULL_STRING) : NULL_STRING; - if (!old_condition.equals(new_condition)) { - breakpoint.setCondition(old_condition); - } - else { - breakpoint.setCondition(NULL_STRING); - } - } catch (CoreException e) { - } - } - - /** - * Indicates if the back-end supports multiple threads for - * this type of breakpoint - * - * @param breakpoint - */ - protected boolean supportsThreads(ICBreakpoint breakpoint) { - - return !(breakpoint instanceof ICWatchpoint); - } - } diff -r 05ea843f7d56 -r 09f3d307f081 cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java --- a/cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java Tue Nov 17 14:33:45 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java Mon Nov 23 00:59:16 2009 -0600 @@ -7,13 +7,14 @@ * * Contributors: * Wind River - Initial API and implementation - * Ericsson - Low-level breakpoints integration + * Ericsson - Low-level breakpoints integration + * Nokia - refactored to work for both GDB and EDC. Nov. 2009. *******************************************************************************/ package org.eclipse.cdt.dsf.debug.service; import java.util.ArrayList; -import java.util.Collections; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -27,7 +28,6 @@ import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; -import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.ThreadSafe; import org.eclipse.cdt.dsf.datamodel.IDMContext; @@ -50,7 +50,9 @@ import org.osgi.framework.BundleContext; /** - * + * see these bugs for design of this service.
+ * - https://bugs.eclipse.org/bugs/show_bug.cgi?id=218557 + * - https://bugs.eclipse.org/bugs/show_bug.cgi?id=292468 */ public class BreakpointsMediator extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointsListener { @@ -72,7 +74,7 @@ /** * DSF Debug service for creating breakpoints. */ - IBreakpoints fBreakpoints; + IBreakpoints fBreakpointsService; /** * Platform breakpoint manager @@ -108,7 +110,6 @@ private static class TargetBP implements ITargetBreakpointInfo { private Map fAttributes; - private Map fAttributesDelta; // not really useful ? private IBreakpointDMContext fTargetBPContext; private IStatus fStatus; @@ -137,7 +138,21 @@ } } - /////////////////////////////////////////////////////////////////////////// + private class PlatformBreakpointInfo { + IBreakpoint breakpoint; + boolean enabled; + // All attributes available from UI, including standard and extended ones. + Map attributes; + + public PlatformBreakpointInfo(IBreakpoint bp, boolean enabled, Map attributes) { + super(); + breakpoint = bp; + this.enabled = enabled; + this.attributes = attributes; + } + } + + /////////////////////////////////////////////////////////////////////////// // Breakpoints tracking /////////////////////////////////////////////////////////////////////////// @@ -153,6 +168,43 @@ private Map>> fPlatformBPs = new HashMap>>(); + /** + * Holds platform breakpoints with all their attributes (standard ones and + * extended ones) from UI. This will be used to check what attributes have + * changed for a breakpoint when the breakpoint is changed. The map is
+ * 1. augmented in doBreakpointsAdded();
+ * 2. updated in breakpointsChanged();
+ * 3. diminished in breakpointsRemoved(); + */ + private Map> fBreakpointAttributes = + new HashMap>(); + + private static class PendingEventInfo { + PendingEventInfo(BreakpointEventType eventType, PlatformBreakpointInfo bpInfo, + Collection bpsTargetDmc, RequestMonitor rm) { + fEventType = eventType; + fBPInfo = bpInfo; + fBPTargetContexts = bpsTargetDmc; + fRequestMonitor = rm; + fAttributeDelta = null; + } + + public PendingEventInfo(BreakpointEventType eventType, Collection updateContexts, + Map attrDelta) { + fEventType = eventType; + fBPTargetContexts = updateContexts; + fAttributeDelta = attrDelta; + fRequestMonitor = null; + fBPInfo = null; + } + + PlatformBreakpointInfo fBPInfo; + RequestMonitor fRequestMonitor; + BreakpointEventType fEventType; + Collection fBPTargetContexts; + Map fAttributeDelta; // for change event only + } + /** * Due to the very asynchronous nature of DSF, a new breakpoint request can * pop up at any time before an ongoing one is completed. The following set @@ -160,23 +212,8 @@ */ private Set fRunningEvents = new HashSet(); - private static class PendingEventInfo { - PendingEventInfo(BreakpointEventType eventType, IBreakpointsTargetDMContext bpsTargetDmc, RequestMonitor rm) { - fEventType = eventType; - fBPsTargetDmc = bpsTargetDmc; - fRequestMonitor = rm; - } - - RequestMonitor fRequestMonitor; - BreakpointEventType fEventType; - IBreakpointsTargetDMContext fBPsTargetDmc; - } - - /** - * @see fPendingRequests - */ private Map> fPendingEvents = - Collections.synchronizedMap(new HashMap>()); + new HashMap>(); /////////////////////////////////////////////////////////////////////////// // AbstractDsfService @@ -219,7 +256,7 @@ private void doInitialize(RequestMonitor rm) { // Get the services references - fBreakpoints = getServicesTracker().getService(IBreakpoints.class); + fBreakpointsService = getServicesTracker().getService(IBreakpoints.class); fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager(); fAttributeTranslator.initialize(this); @@ -328,12 +365,15 @@ // Remove the breakpoints for given DMC from the internal maps. Map> platformBPs = fPlatformBPs.get(dmc); - if (platformBPs == null) { - rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Breakpoints not installed for given context", null)); //$NON-NLS-1$ + if (platformBPs == null || platformBPs.size() == 0) { + rm.setStatus(new Status(IStatus.INFO /* NOT error */, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Breakpoints not installed for given context", null)); //$NON-NLS-1$ rm.done(); return; } - + + // Just remove the IBreakpoints installed for the "dmc". + final IBreakpoint[] bps = platformBPs.keySet().toArray(new IBreakpoint[platformBPs.size()]); + new Job("Uninstall target breakpoints list.") { //$NON-NLS-1$ { setSystem(true); } @@ -341,7 +381,7 @@ // and install them on the target @Override protected IStatus run(IProgressMonitor monitor) { - doBreakpointsRemoved(DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(), dmc, rm); + doBreakpointsRemoved(bps, dmc, rm); return Status.OK_STATUS; } }.schedule(); @@ -356,6 +396,8 @@ * @return array of target breakpoints. */ public ITargetBreakpointInfo[] getTargetBreakpoints(IBreakpointsTargetDMContext dmc, IBreakpoint platformBp) { + assert getExecutor().isInExecutorThread(); + Map> platformBPs = fPlatformBPs.get(dmc); if (platformBPs != null) @@ -376,6 +418,8 @@ * @return platform breakpoint. null if not found. */ public IBreakpoint getPlatformBreakpoint(IBreakpointsTargetDMContext dmc, IBreakpointDMContext bp) { + assert getExecutor().isInExecutorThread(); + for (IBreakpointsTargetDMContext bpContext : fPlatformBPs.keySet()) { if (dmc != null && !dmc.equals(bpContext)) continue; @@ -448,7 +492,7 @@ // Install the back-end breakpoint(s) for (int _i = 0; _i < attrsList.size(); _i++) { final int i = _i; - fBreakpoints.insertBreakpoint( + fBreakpointsService.insertBreakpoint( dmc, attrsList.get(i), new DataRequestMonitor(getExecutor(), installRM) { @Override @@ -508,16 +552,14 @@ for (int i = 0; i < bpList.size(); i++) { final TargetBP bp = bpList.get(i); if (bp.getTargetBreakpoint() != null) { - fBreakpoints.removeBreakpoint( + fBreakpointsService.removeBreakpoint( bp.getTargetBreakpoint(), new RequestMonitor(getExecutor(), countingRm) { @Override protected void handleCompleted() { bp.setStatus(getStatus()); - bp.fAttributesDelta = bp.fAttributes; if (isSuccess()) { bp.setTargetBreakpoint(null); - bp.fAttributes = null; } countingRm.done(); } @@ -530,225 +572,12 @@ countingRm.setDoneCount(count); } - /** - * Modify an individual breakpoint - * - * @param context - * @param breakpoint - * @param attributes - * @param drm - * @throws CoreException - */ - private void modifyBreakpoint(final IBreakpointsTargetDMContext context, final IBreakpoint breakpoint, - final List> newAttrsList, final DataRequestMonitor> drm) - { - // This method uses several lists to track the changed breakpoints: - // commonAttrsList - attributes which have not changed - // oldAttrsList - attributes for the breakpoint before the change - // newAttrsList - attributes for the breakpoint after the change - // oldBpContexts - target-side breakpoints from before the change - // newBpContexts - target-side breakpoints after the change - // attrDeltasList - changes in the attributes for each attribute map in - // oldAttrsList and newAttrsList - - // Get the maps - final Map> platformBPs = fPlatformBPs.get(context); - if (platformBPs == null) { - drm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ - drm.done(); - return; - } - - final List oldBpList = platformBPs.get(breakpoint); - - final List bpList = new ArrayList(newAttrsList.size()); - - if (oldBpList == null || oldBpList.size() == 0) { // not targetBP installed - drm.setData(bpList); - drm.done(); - return; - } - - for (int i = 0; i < newAttrsList.size(); i++) { - bpList.add(new TargetBP(newAttrsList.get(i))); - } - - // Create a list of attribute changes. The length of this list will - // always be max(oldAttrList.size(), newAttrsList.size()), padded with - // null's if oldAttrsList was longer. - calcBPsAttrs(oldBpList, bpList); - - // Create the request monitor that will be called when all - // modifying/inserting/removing is complete. - final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), drm) { - @Override - protected void handleCompleted() { - // Save the new list of target breakpoints - platformBPs.put(breakpoint, bpList); - drm.setData(bpList); - drm.done(); - } - }; - - // Set the count, if could be zero if no breakpoints have actually changed. - int coutingRmCount = 0; - - // Process the changed breakpoints. - for (int _i = 0; _i < bpList.size(); _i++) { - final int i = _i; - final TargetBP bp = bpList.get(i); - if (bp.fAttributes == null) { - // The list of new attribute maps was shorter than the old. - // Remove the corresponding target-side bp. - // Note the target BP context may be null if the target - // BP failed to insert in the first place. - if (bp.getTargetBreakpoint() != null) { - fBreakpoints.removeBreakpoint( - bp.getTargetBreakpoint(), - new RequestMonitor(getExecutor(), countingRM) { - @Override - protected void handleCompleted() { - bp.fStatus = getStatus(); - countingRM.done(); - } - }); - coutingRmCount++; - } - } else if ( bp.getTargetBreakpoint() == null) { - // The list of new attribute maps was longer, just insert - // the new breakpoint - final Map attrs = newAttrsList.get(i); - fBreakpoints.insertBreakpoint( - context, attrs, - new DataRequestMonitor(getExecutor(), countingRM) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - bp.fTargetBPContext = getData(); - } - bp.fStatus = getStatus(); - countingRM.done(); - } - }); - coutingRmCount++; - } else if (bp.fAttributesDelta.size() == 0) { - // Breakpoint attributes have not changed, only copy over the old status. - bp.fStatus = oldBpList.get(i).fStatus; - } else if ( !fAttributeTranslator.canUpdateAttributes(bp.getTargetBreakpoint(), bp.fAttributesDelta) ) { - // The attribute translator tells us that the debugger cannot modify the - // breakpoint to change the given attributes. Remove the breakpoint - // and insert a new one. - RequestMonitor removeRm = new RequestMonitor(getExecutor(), countingRM) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - bp.fTargetBPContext = null; - fBreakpoints.insertBreakpoint( - context, newAttrsList.get(i), - new DataRequestMonitor(getExecutor(), countingRM) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - bp.fTargetBPContext = getData(); - } - bp.fStatus = getStatus(); - countingRM.done(); - } - }); - } else { - // Failed to remove old breakpoint, do not proceed to insert a new one - // just save the error from target with the old context. - bp.fStatus = getStatus(); - countingRM.done(); - } - } - }; - - fBreakpoints.removeBreakpoint(bp.getTargetBreakpoint(), removeRm); - coutingRmCount++; - } else { - // The back end can modify the breakpoint. Update the breakpoint with the - // new attributes. - fBreakpoints.updateBreakpoint( - bp.getTargetBreakpoint(), bp.fAttributes, - new RequestMonitor(getExecutor(), countingRM) { - @Override - protected void handleCompleted() { - bp.fStatus = getStatus(); - countingRM.done(); - } - }); - coutingRmCount++; - } - } - countingRM.setDoneCount(coutingRmCount); - } - - /** - * Determine the set of modified attributes - * - * @param oldAttributes - * @param newAttributes - * @return - */ - private void calcBPsAttrs(List oldBpList, List bpList) { - // Go through the bp attributes common to the old and the new lists and calculate - // their deltas. - int i = 0; - for (i = 0; i < oldBpList.size() && i < bpList.size(); i++) { - TargetBP newBp = bpList.get(i); - TargetBP oldBp = oldBpList.get(i); - newBp.fTargetBPContext = oldBp.getTargetBreakpoint(); - Map oldAttributes = oldBp.fAttributes; - Map newAttributes = newBp.fAttributes; - - if (oldAttributes == null) { - // Reached a point in the old BP list where breakpoints were - // removed. Break out of the loop. - break; - } - - bpList.get(i).fAttributesDelta = getAttributesDelta(oldAttributes, newAttributes); - } - - // Add all the new attributes as deltas - for (; i < bpList.size(); i++) { - TargetBP newBP = bpList.get(i); - newBP.fAttributesDelta = newBP.fAttributes; - } - - // For breakpoints that were removed create TargetBP entry with a - // null set of attributes - for (; i < oldBpList.size(); i++) { - TargetBP oldBp = oldBpList.get(i); - if (oldBp.fAttributes == null) { - // Guard against old removed breakpoints - break; - } - TargetBP newBp = new TargetBP(null); - newBp.fTargetBPContext = oldBp.getTargetBreakpoint(); - newBp.fAttributesDelta = oldBpList.get(i).fAttributes; - bpList.add(newBp); - } - } - /////////////////////////////////////////////////////////////////////////// // IBreakpointManagerListener implementation /////////////////////////////////////////////////////////////////////////// public void breakpointManagerEnablementChanged(boolean enabled) { - Map platformAttrDelta = new HashMap(1); - platformAttrDelta.put(IBreakpoint.ENABLED, enabled); - - Map> bp2DeltaMap = new HashMap>(); - for (IBreakpoint bp : fBreakpointManager.getBreakpoints()) { - if (! fAttributeTranslator.supportsBreakpoint(bp)) - continue; - - bp2DeltaMap.put(bp, platformAttrDelta); - } - - doBreakpointsChanged(bp2DeltaMap); + // do nothing. breakpointsChanged() will be called to handle the change. } @ThreadSafe @@ -756,141 +585,30 @@ doBreakpointsAdded(bps, null, null); } - @SuppressWarnings("unchecked") - private void doBreakpointsAdded(final IBreakpoint[] bps, final IBreakpointsTargetDMContext bpsTargetDmc, final RequestMonitor rm) { - final List bpCandidates = new ArrayList(bps.length); - - for (int i = 0; i < bps.length; i++) { - IBreakpoint bp = bps[i]; - - if (fAttributeTranslator.supportsBreakpoint(bp)) { - try { - if (fAttributeTranslator2 != null) { - if (bp.getMarker() == null) - continue; - - // if the breakpoint is not enabled, ask translator2 if it can set (and manage) - // disabled breakpoint itself. If not, just bail out. - // - Map platformAttrs = bp.getMarker().getAttributes(); - - if (! (Boolean)platformAttrs.get(IBreakpoint.ENABLED) || ! fBreakpointManager.isEnabled()) { - Map platformAttr = new HashMap(1); - platformAttr.put(IBreakpoint.ENABLED, Boolean.FALSE); - Map targetAttr = fAttributeTranslator2.convertAttributeDelta(platformAttr); - if (! fAttributeTranslator2.canUpdateAttributes(null, targetAttr)) { - // bail out. - continue; - } - } - } - - bpCandidates.add(bp); - } catch (CoreException e) { - DsfPlugin.getDefault().getLog().log(e.getStatus()); - } - } - } + protected void doBreakpointsAdded(final IBreakpoint[] bps, final IBreakpointsTargetDMContext bpsTargetDmc, final RequestMonitor rm) { + // Collect attributes (which will access system resource) + // in non DSF dispatch thread. + // + final PlatformBreakpointInfo[] bpsInfo = collectBreakpointsInfo(bps); // Nothing to do - if (bpCandidates.isEmpty()) { + if (bpsInfo.length == 0) { if (rm != null) { rm.done(); } return; } - + try { getExecutor().execute(new DsfRunnable() { public void run() { - final Map> eventBPs = - new HashMap>(bpCandidates.size(), 1); - - CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleCompleted() { - processPendingRequests(); - fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.ADDED); - super.handleCompleted(); - } - }; - int processPendingCountingRmCount = 0; - - for (final IBreakpoint breakpoint : bpCandidates) { - final Map targetBPs = - new HashMap(fPlatformBPs.size(), 1); - eventBPs.put(breakpoint, targetBPs); - - if (fRunningEvents.contains(breakpoint)) { - PendingEventInfo pendingEvent = new PendingEventInfo(BreakpointEventType.ADDED, bpsTargetDmc, processPendingCountingRm); - processPendingCountingRmCount++; - updatePendingRequest(breakpoint, pendingEvent); - continue; - } - // Mark the breakpoint as being updated and go - fRunningEvents.add(breakpoint); + Collection dmcs = new ArrayList(); + if (bpsTargetDmc == null) + dmcs.addAll(fPlatformBPs.keySet()); + else + dmcs.add(bpsTargetDmc); - final CountingRequestMonitor bpTargetsCountingRm = new CountingRequestMonitor(getExecutor(), processPendingCountingRm) { - @Override - protected void handleCompleted() { - // Indicate that the running event has completed - fRunningEvents.remove(breakpoint); - super.handleCompleted(); - } - }; - int bpTargetsCountingRmCount = 0; - processPendingCountingRmCount++; - - - // Install the breakpoint in all the execution contexts - for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { - if (bpsTargetDmc != null && !bpsTargetDmc.equals(dmc)) { - continue; - } - - // Now ask lower level to set the bp. - // - if (fAttributeTranslator2 != null) { - fAttributeTranslator2.getTargetBreakpointAttributes(dmc, breakpoint, fBreakpointManager.isEnabled(), - new DataRequestMonitor>>(getExecutor(), bpTargetsCountingRm){ - @Override - protected void handleSuccess() { - installBreakpoint( - dmc, breakpoint, getData(), - new DataRequestMonitor>(getExecutor(), bpTargetsCountingRm) { - @Override - protected void handleSuccess() { - targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()])); - super.handleSuccess(); - }; - }); - }}); - } - else { // Old way - List> attrsArray; - try { - attrsArray = fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled()); - } catch (CoreException e) { - attrsArray = new ArrayList>(); - DsfPlugin.getDefault().getLog().log(e.getStatus()); - } - - installBreakpoint( - dmc, breakpoint, attrsArray, - new DataRequestMonitor>(getExecutor(), bpTargetsCountingRm) { - @Override - protected void handleSuccess() { - targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()])); - super.handleSuccess(); - }; - }); - } - - bpTargetsCountingRmCount++; - } - bpTargetsCountingRm.setDoneCount(bpTargetsCountingRmCount); - } - processPendingCountingRm.setDoneCount(processPendingCountingRmCount); + doBreakpointsAddedInExecutor(bpsInfo, dmcs, rm); } }); } catch (RejectedExecutionException e) { @@ -904,191 +622,278 @@ } } - /////////////////////////////////////////////////////////////////////////// - // IBreakpointListener implementation - /////////////////////////////////////////////////////////////////////////// - - @SuppressWarnings("unchecked") - public void breakpointsChanged(IBreakpoint[] bps, IMarkerDelta[] deltas) { - Map> bp2DeltaMap = new HashMap>(); - for (int i = 0; i < bps.length; i++) { - IBreakpoint bp = bps[i]; - - if (deltas[i] == null) - continue; - + /** + * Collect breakpoint info. This method must not be called in DSF dispatch thread. + * @param bps + * @return + */ + private PlatformBreakpointInfo[] collectBreakpointsInfo(IBreakpoint[] bps) { + List bpsInfo = new ArrayList(bps.length); + + for (IBreakpoint bp : bps) { if (bp.getMarker() == null) continue; - if (! fAttributeTranslator.supportsBreakpoint(bp)) - continue; - - try { - Map oldAttrs = deltas[i].getAttributes(); - Map newAttrs = bp.getMarker().getAttributes(); - - Map platformAttrDelta = getAttributesDelta(oldAttrs, newAttrs); - - if (platformAttrDelta.size() == 0) // no change. possible when user cancels breakpoint properties dialog. - continue; - - bp2DeltaMap.put(bp, platformAttrDelta); - } catch (CoreException e) { - DsfPlugin.getDefault().getLog().log(e.getStatus()); + if (fAttributeTranslator.supportsBreakpoint(bp)) { + try { + Map attrs = fAttributeTranslator2.getAllBreakpointAttributes(bp, fBreakpointManager.isEnabled()); + boolean enabled = bp.isEnabled() && fBreakpointManager.isEnabled(); + bpsInfo.add(new PlatformBreakpointInfo(bp, enabled, attrs)); + } catch (CoreException e) { + DsfPlugin.getDefault().getLog().log(e.getStatus()); + } } } - doBreakpointsChanged(bp2DeltaMap); + return bpsInfo.toArray(new PlatformBreakpointInfo[bpsInfo.size()]); } - - /** - * - * @param bp2DeltaMap - pairs of (breakpoint, attrDelta), where attrDelta contains changed - * and new attributes for the breakpoint. - */ - private void doBreakpointsChanged(Map> bp2DeltaMap) { - final Map>> bpsAttrs = - new HashMap>>(bp2DeltaMap.size() * 4/3); - - for (IBreakpoint bp : bp2DeltaMap.keySet()) { - try { - Map platformAttrDelta = bp2DeltaMap.get(bp); - - if (fAttributeTranslator2 != null) { - Map targetAttrDelta = fAttributeTranslator2.convertAttributeDelta(platformAttrDelta); + protected void doBreakpointsAddedInExecutor(PlatformBreakpointInfo[] bpsInfo, Collection bpTargetDMCs, RequestMonitor rm) { + final Map> eventBPs = + new HashMap>(bpsInfo.length, 1); - if (! fAttributeTranslator2.canUpdateAttributes(null, targetAttrDelta)) { - // DSF client cannot handle at least one of the attribute change, just remove - // old target BPs and install new ones. - final IBreakpoint[] platformBPs = new IBreakpoint[] {bp}; - - if (platformAttrDelta.containsKey(IBreakpoint.ENABLED)) { - if ((Boolean)platformAttrDelta.get(IBreakpoint.ENABLED)) - // platform BP changed from disabled to enabled - doBreakpointsAdded(platformBPs, null, null); - else - doBreakpointsRemoved(platformBPs, null, null); - } - else { - // other attribute change, remove old and install new. - doBreakpointsRemoved(platformBPs, null, new RequestMonitor(getExecutor(), null) { - @Override - protected void handleSuccess() { - doBreakpointsAdded(platformBPs, null, null); - }}); - } + CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + processPendingRequests(); + fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.ADDED); + super.handleCompleted(); + } + }; + int processPendingCountingRmCount = 0; + + for (final PlatformBreakpointInfo bpinfo : bpsInfo) { + final Map targetBPs = + new HashMap(fPlatformBPs.size(), 1); + eventBPs.put(bpinfo.breakpoint, targetBPs); + + // Remember the new attributes of the bp in our global buffer, + // even if we cannot or fail to install the bp. + fBreakpointAttributes.put(bpinfo.breakpoint, bpinfo.attributes); + + if (fRunningEvents.contains(bpinfo.breakpoint)) { + PendingEventInfo pendingEvent = new PendingEventInfo(BreakpointEventType.ADDED, bpinfo, bpTargetDMCs, processPendingCountingRm); + processPendingCountingRmCount++; + updatePendingRequest(bpinfo.breakpoint, pendingEvent); + continue; + } + + processPendingCountingRmCount++; + + // Mark the breakpoint as being updated and go + fRunningEvents.add(bpinfo.breakpoint); + + final CountingRequestMonitor bpTargetsCountingRm = new CountingRequestMonitor(getExecutor(), processPendingCountingRm) { + @Override + protected void handleCompleted() { + // Indicate that the running event has completed + fRunningEvents.remove(bpinfo.breakpoint); + super.handleCompleted(); + } + }; + + int bpTargetsCountingRmCount = 0; + + // Install the breakpoint in all the execution contexts + for (final IBreakpointsTargetDMContext dmc : bpTargetDMCs) { + + // Now ask lower level to set the bp. + // + // if the breakpoint is disabled, ask back-end if it can set (and manage) + // disabled breakpoint. If not, just bail out. + // + if (! bpinfo.enabled) { + Map attr = new HashMap(1); + attr.put(IBreakpoint.ENABLED, Boolean.FALSE); + Map targetEnablementAttr = fAttributeTranslator2.convertAttributes(attr); + if (! fAttributeTranslator2.canUpdateAttributes(bpinfo.breakpoint, dmc, targetEnablementAttr)) { + // bail out. Continue with the next dmc & breakpoint. + continue; } - else - updateBreakpoint(bp, targetAttrDelta); } - else { // old way - - // Retrieve the breakpoint attributes - List> attrsArray = - fAttributeTranslator.getBreakpointAttributes(bp, fBreakpointManager.isEnabled()); - - bpsAttrs.put(bp, attrsArray); - } - } catch (CoreException e) { - DsfPlugin.getDefault().getLog().log(e.getStatus()); + + // Now do the real work. + // + fAttributeTranslator2.resolveBreakpoint(dmc, bpinfo.breakpoint, bpinfo.attributes, + new DataRequestMonitor>>(getExecutor(), bpTargetsCountingRm){ + @Override + protected void handleSuccess() { + installBreakpoint( + dmc, bpinfo.breakpoint, getData(), + new DataRequestMonitor>(getExecutor(), bpTargetsCountingRm) { + @Override + protected void handleSuccess() { + targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()])); + super.handleSuccess(); + }; + }); + }}); + + bpTargetsCountingRmCount++; } - } + + bpTargetsCountingRm.setDoneCount(bpTargetsCountingRmCount); + } + + processPendingCountingRm.setDoneCount(processPendingCountingRmCount); + } + + /* + * Note this method must not be called in DSF dispatch thread. + * + * @param bps + * @param deltas + */ + public void breakpointsChanged(IBreakpoint[] bps, IMarkerDelta[] deltas) { + if (fAttributeTranslator2 == null) + return; - if (bpsAttrs.isEmpty()) return; // nothing to do + final PlatformBreakpointInfo[] bpsInfo = collectBreakpointsInfo(bps); + + if (bpsInfo.length == 0) + return; // nothing to do try { - // Modify the breakpoint in all the target contexts getExecutor().execute( new DsfRunnable() { public void run() { - final Map> eventBPs = - new HashMap>(bpsAttrs.size(), 1); + Map tmp = new HashMap(1); + tmp.put(IBreakpoint.ENABLED, true); + final String targetEnablementKey = fAttributeTranslator2.convertAttributes(tmp).keySet().iterator().next(); - CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), null) { - @Override - protected void handleCompleted() { - processPendingRequests(); - fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.MODIFIED); - } - }; - int processPendingCountingRmCount = 0; - - for (final IBreakpoint breakpoint : bpsAttrs.keySet()) { - final Map targetBPs = - new HashMap(fPlatformBPs.size(), 1); - eventBPs.put(breakpoint, targetBPs); - - // If the breakpoint is currently being updated, queue the request and exit - if (fRunningEvents.contains(breakpoint)) { - updatePendingRequest(breakpoint, new PendingEventInfo(BreakpointEventType.MODIFIED, null, null)); + for (PlatformBreakpointInfo bpinfo : bpsInfo) { + /* + * We cannot depend on "deltas" for attribute change. + * For instance, delta can be null when extended + * attributes (e.g. breakpoint thread filter for GDB) + * are changed. + */ + Map newAttrs = bpinfo.attributes; + Map oldAttrs = fBreakpointAttributes.get(bpinfo.breakpoint); + + // remember the new attributes. + fBreakpointAttributes.put(bpinfo.breakpoint, newAttrs); + + final Map attrDelta = getAttributesDelta(oldAttrs, newAttrs); + if (attrDelta.size() == 0) continue; - } - - // Keep track of the updates - CountingRequestMonitor bpTargetsCountingRm = - new CountingRequestMonitor(getExecutor(), processPendingCountingRm) { - @Override - protected void handleCompleted() { - // Indicate that the running event has completed - fRunningEvents.remove(breakpoint); - super.handleCompleted(); - } - }; - processPendingCountingRmCount++; - bpTargetsCountingRm.setDoneCount(fPlatformBPs.size()); - - // Mark the breakpoint as being updated and go - fRunningEvents.add(breakpoint); - - // Modify the breakpoint in all the execution contexts - for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { - modifyBreakpoint( - dmc, breakpoint, bpsAttrs.get(breakpoint), - new DataRequestMonitor>(getExecutor(), bpTargetsCountingRm) { - @Override - protected void handleSuccess() { - targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()])); - super.handleSuccess(); - }; - }); - } + + final List reinstallContexts = new ArrayList(); + + List updateContexts = new ArrayList(); + + // Now change the breakpoint for each known context. + // + for (final IBreakpointsTargetDMContext btContext : fPlatformBPs.keySet()) { + + if (! fAttributeTranslator2.canUpdateAttributes(bpinfo.breakpoint, btContext, attrDelta)) { + // backend cannot handle at least one of the platform BP attribute change, + // we'll handle the re-installation. + reinstallContexts.add(btContext); + } + else { + // Backend claims it can handle the attributes change, let it do it. + updateContexts.add(btContext); + } + + } + + final PlatformBreakpointInfo[] oneBPInfo = new PlatformBreakpointInfo[] {bpinfo}; + IBreakpoint[] oneBP = new IBreakpoint[] {bpinfo.breakpoint}; + + if (reinstallContexts.size() > 0) { + // Check if it's only enablement change (user click enable/disable + // button or "Skip all breakpoints" button), which is common operation. + // + if (attrDelta.size() == 1 && attrDelta.containsKey(targetEnablementKey)) { // only enablement changed. + if (bpinfo.enabled) { + // change from disable to enable. Install the bp. + doBreakpointsAddedInExecutor(oneBPInfo, reinstallContexts, null); + } + else { + // change from enable to disable. Remove the bp. + doBreakpointsRemovedInExecutor(oneBP, reinstallContexts, null); + } + } + else { + doBreakpointsRemovedInExecutor(oneBP, reinstallContexts, new RequestMonitor(getExecutor(), null) { + // What should we do if removal of some or all targetBP fails ? + // Go on with the installation of new targetBPs and let clients (i.e. AttributeTranslators) + // handle the errors. + @Override + protected void handleCompleted() { + doBreakpointsAddedInExecutor(oneBPInfo, reinstallContexts, null); + }}); + } + } + + if (updateContexts.size() > 0) + modifyTargetBreakpoints(bpinfo.breakpoint, updateContexts, attrDelta); } - processPendingCountingRm.setDoneCount(processPendingCountingRmCount); } }); } catch (RejectedExecutionException e) { DsfPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in a rejected execution exception.", e)); //$NON-NLS-1$ //$NON-NLS-2$ } + } /** - * For the given platform BP, update all its target BPs with the given attribute change. + * For the given platform BP, ask the backend to modify all its target BPs + * with the given attribute change.
+ * This must be called in DSF executor thread. * * @param bp - * @param targetAttrDelta - target attribute change. + * @param updateContexts + * target contexts in which to do the modification. + * @param targetAttrDelta + * target-recognizable attribute(s) with new values. */ - private void updateBreakpoint(final IBreakpoint bp, final Map targetAttrDelta) { - getExecutor().execute(new DsfRunnable() { - public void run() { - for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { - List targetBPs = fPlatformBPs.get(dmc).get(bp); - if (targetBPs != null) { - for (TargetBP tbp : targetBPs) { - // this must be an installed bp. - assert (tbp.getTargetBreakpoint() != null); - - fBreakpoints.updateBreakpoint(tbp.getTargetBreakpoint(), targetAttrDelta, new RequestMonitor(getExecutor(), null) {}); - } - } + private void modifyTargetBreakpoints(final IBreakpoint bp, Collection updateContexts, Map targetAttrDelta) { + // If the breakpoint is currently being updated, queue the request and exit + if (fRunningEvents.contains(bp)) { + PendingEventInfo pendingEvent = new PendingEventInfo(BreakpointEventType.MODIFIED, updateContexts, targetAttrDelta); + updatePendingRequest(bp, pendingEvent); + return; + } + + CountingRequestMonitor modifyTargetBPCRM = new CountingRequestMonitor(getExecutor(), null) { + @Override + protected void handleCompleted() { + fRunningEvents.remove(bp); + }}; + + int targetBPCount = 0; + + fRunningEvents.add(bp); + + for (IBreakpointsTargetDMContext context : updateContexts) { + List targetBPs = fPlatformBPs.get(context).get(bp); + if (targetBPs != null) { + for (TargetBP tbp : targetBPs) { + // this must be an installed breakpoint. + assert (tbp.getTargetBreakpoint() != null); + + targetBPCount++; + fBreakpointsService.updateBreakpoint(tbp.getTargetBreakpoint(), targetAttrDelta, modifyTargetBPCRM); } - }}); + } + } + + modifyTargetBPCRM.setDoneCount(targetBPCount); } public void breakpointsRemoved(final IBreakpoint[] bps, IMarkerDelta delta[]) { + getExecutor().execute(new DsfRunnable() { + public void run() { + for (IBreakpoint bp : bps) + fBreakpointAttributes.remove(bp); + } + }); + doBreakpointsRemoved(bps, null, null); } - public void doBreakpointsRemoved(final IBreakpoint[] bps, final IBreakpointsTargetDMContext bpsTargetDmc, final RequestMonitor rm) { + protected void doBreakpointsRemoved(final IBreakpoint[] bps, final IBreakpointsTargetDMContext bpsTargetDmc, final RequestMonitor rm) { final List bpCandidates = new ArrayList(); @@ -1096,10 +901,7 @@ IBreakpoint bp = bps[i]; if (fAttributeTranslator.supportsBreakpoint(bp)) { - if (bpsTargetDmc == null) - bpCandidates.add(bp); - else if (fPlatformBPs.get(bpsTargetDmc).containsKey(bp)) // target BPs are installed in the context - bpCandidates.add(bp); + bpCandidates.add(bp); } } @@ -1112,72 +914,18 @@ try { getExecutor().execute(new DsfRunnable() { public void run() { - final Map> eventBPs = - new HashMap>(bpCandidates.size(), 1); + Collection contexts = new ArrayList(); + if (bpsTargetDmc == null) + contexts.addAll(fPlatformBPs.keySet()); + else + contexts.add(bpsTargetDmc); - CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleCompleted() { - processPendingRequests(); - fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.REMOVED); - super.handleCompleted(); - } - }; - int processPendingCountingRmCount = 0; - - for (final IBreakpoint breakpoint : bpCandidates) { - final Map targetBPs = - new HashMap(fPlatformBPs.size(), 1); - eventBPs.put(breakpoint, targetBPs); - - // If the breakpoint is currently being updated, queue the request and exit - if (fRunningEvents.contains(breakpoint)) { - PendingEventInfo pendingEvent = new PendingEventInfo(BreakpointEventType.REMOVED, bpsTargetDmc, processPendingCountingRm); - processPendingCountingRmCount++; - updatePendingRequest(breakpoint, pendingEvent); - continue; - } - - CountingRequestMonitor bpTargetDmcCRM = new CountingRequestMonitor(getExecutor(), processPendingCountingRm) { - @Override - protected void handleCompleted() { - // Indicate that the running event has completed - fRunningEvents.remove(breakpoint); - super.handleCompleted(); - } - }; - processPendingCountingRmCount++; - int bpTargetDmcCRMCount = 0; - - // Remove the breakpoint in all the execution contexts - for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { - if (bpsTargetDmc != null && !bpsTargetDmc.equals(dmc)) { - continue; - } - - if (fPlatformBPs.get(dmc).containsKey(breakpoint)) { // there are targetBPs installed - uninstallBreakpoint( - dmc, breakpoint, - new DataRequestMonitor>(getExecutor(), bpTargetDmcCRM) { - @Override - protected void handleSuccess() { - targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()])); - super.handleSuccess(); - }; - }); - bpTargetDmcCRMCount++; - } else { - // Breakpoint not installed for given context, do nothing. - } - } - bpTargetDmcCRM.setDoneCount(bpTargetDmcCRMCount); - } - - processPendingCountingRm.setDoneCount(processPendingCountingRmCount); + doBreakpointsRemovedInExecutor(bpCandidates.toArray(new IBreakpoint[bpCandidates.size()]), contexts, rm); } }); } catch (RejectedExecutionException e) { - IStatus status = new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in a rejected execution exception.", e);//$NON-NLS-1$ //$NON-NLS-2$ + IStatus status = new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, + "Request for monitor: '" + toString() + "' resulted in a rejected execution exception.", e);//$NON-NLS-1$ //$NON-NLS-2$ if (rm != null) { rm.setStatus(status); rm.done(); @@ -1187,6 +935,79 @@ } } + protected void doBreakpointsRemovedInExecutor(IBreakpoint[] bpCandidates, + Collection targetContexts, RequestMonitor rm) { + + final Map> eventBPs = + new HashMap>(bpCandidates.length, 1); + + CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + processPendingRequests(); + fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.REMOVED); + super.handleCompleted(); + } + }; + int processPendingCountingRmCount = 0; + + for (final IBreakpoint breakpoint : bpCandidates) { + + // If the breakpoint is currently being updated, queue the request and exit + if (fRunningEvents.contains(breakpoint)) { + PendingEventInfo pendingEvent = new PendingEventInfo(BreakpointEventType.REMOVED, null, targetContexts, processPendingCountingRm); + processPendingCountingRmCount++; + updatePendingRequest(breakpoint, pendingEvent); + continue; // handle next breakpoint + } + + processPendingCountingRmCount++; + + final Map targetBPs = + new HashMap(fPlatformBPs.size(), 1); + eventBPs.put(breakpoint, targetBPs); + + CountingRequestMonitor bpTargetsCountingRM = new CountingRequestMonitor(getExecutor(), processPendingCountingRm) { + @Override + protected void handleCompleted() { + // Indicate that the running event has completed + fRunningEvents.remove(breakpoint); + super.handleCompleted(); + } + }; + + int bpTargetsCoutingRMCount = 0; + + // Mark the breakpoint as being updated and go + fRunningEvents.add(breakpoint); + + // Remove the breakpoint in all the execution contexts + for (final IBreakpointsTargetDMContext dmc : targetContexts) { + + if (fPlatformBPs.get(dmc).containsKey(breakpoint)) { // there are targetBPs installed + // now do time-consuming part of the work. + + uninstallBreakpoint( + dmc, breakpoint, + new DataRequestMonitor>(getExecutor(), bpTargetsCountingRM) { + @Override + protected void handleSuccess() { + targetBPs.put(dmc, getData().toArray(new ITargetBreakpointInfo[getData().size()])); + super.handleSuccess(); + }; + }); + bpTargetsCoutingRMCount++; + } else { + // Breakpoint not installed for given context, do nothing. + } + } + + bpTargetsCountingRM.setDoneCount(bpTargetsCoutingRMCount); + } + + processPendingCountingRm.setDoneCount(processPendingCountingRmCount); + } + private void updatePendingRequest(IBreakpoint breakpoint, PendingEventInfo pendingEvent) { LinkedList pendingEventsList = fPendingEvents.get(breakpoint); if (pendingEventsList == null) { @@ -1201,91 +1022,38 @@ } private void processPendingRequests() { + /* + * This will process only first pending request for each breakpoint, + * whose RequestMonitor (see "processPendingCountingRm" in such methods as + * doBreakpointsRemovedInExecutor()) will invoke this method again. + */ if (fPendingEvents.isEmpty()) return; // Nothing to do - final List modifyBPs = new ArrayList(1); - final Map> addBPs = - new HashMap>(1); - final Map> removeBPs = - new HashMap>(1); - - // Make a copy to avoid java.util.ConcurrentModificationException. + // Make a copy to avoid ConcurrentModificationException + // as we are deleting element in the loop. Set bpsInPendingEvents = new HashSet(fPendingEvents.keySet()); -// for (IBreakpoint bp : fPendingEvents.keySet()) { for (IBreakpoint bp : bpsInPendingEvents) { - // Process the next pending update for this breakpoint - if (!fRunningEvents.contains(bp)) { - LinkedList eventInfoList = fPendingEvents.get(bp); - PendingEventInfo eventInfo = eventInfoList.removeFirst(); - if (eventInfoList.isEmpty()) { - fPendingEvents.remove(bp); - } - BreakpointEventType type = eventInfo.fEventType; - if (type.equals(BreakpointEventType.MODIFIED)) { - modifyBPs.add(eventInfo); - } else if (type.equals(BreakpointEventType.ADDED)){ - List addList = addBPs.get(eventInfo.fBPsTargetDmc); - if (addList == null) { - addList = new ArrayList(1); - addBPs.put(eventInfo.fBPsTargetDmc, addList); - } - addList.add(eventInfo); - } else if (type.equals(BreakpointEventType.REMOVED)){ - List removeList = removeBPs.get(eventInfo.fBPsTargetDmc); - if (removeList == null) { - removeList = new ArrayList(1); - removeBPs.put(eventInfo.fBPsTargetDmc, removeList); - } - removeList.add(eventInfo); - } - } - } + if (! fRunningEvents.contains(bp)) { + LinkedList eventInfoList = fPendingEvents.get(bp); - if (modifyBPs.size() != 0 || removeBPs.size() != 0) { - new Job("Deferred breakpoint changed job") { //$NON-NLS-1$ - { setSystem(true); } - @Override - protected IStatus run(IProgressMonitor monitor) { - if (modifyBPs.size() != 0) { - breakpointsChanged(modifyBPs.toArray(new IBreakpoint[modifyBPs.size()]), null); - } - if (addBPs.size() != 0) { - for (Map.Entry> addBPsEntry : addBPs.entrySet()) { - IBreakpointsTargetDMContext bpsTargetDmc = addBPsEntry.getKey(); - final List addBpList = addBPsEntry.getValue(); - RequestMonitor rm = new RequestMonitor(ImmediateExecutor.getInstance(), null) { - @Override - protected void handleCompleted() { - for (PendingEventInfo eventInfo : addBpList) { - if (eventInfo.fRequestMonitor != null) { - eventInfo.fRequestMonitor.done(); - } - } - }; - }; - doBreakpointsAdded(addBpList.toArray(new IBreakpoint[addBpList.size()]), bpsTargetDmc, rm); - } - } - if (removeBPs.size() != 0) { - for (Map.Entry> removeBPsEntry : removeBPs.entrySet()) { - IBreakpointsTargetDMContext bpsTargetDmc = removeBPsEntry.getKey(); - final List removeBpList = removeBPsEntry.getValue(); - RequestMonitor rm = new RequestMonitor(ImmediateExecutor.getInstance(), null) { - @Override - protected void handleCompleted() { - for (PendingEventInfo eventInfo : removeBpList) { - if (eventInfo.fRequestMonitor != null) { - eventInfo.fRequestMonitor.done(); - } - } - }; - }; - doBreakpointsRemoved(removeBpList.toArray(new IBreakpoint[removeBpList.size()]), bpsTargetDmc, rm); - } - } - return Status.OK_STATUS; - }; - }.schedule(); + // Process the first pending request for this breakpoint + PendingEventInfo eventInfo = eventInfoList.removeFirst(); + + if (eventInfoList.isEmpty()) + fPendingEvents.remove(bp); + + switch (eventInfo.fEventType) { + case ADDED: + doBreakpointsAddedInExecutor(new PlatformBreakpointInfo[] {eventInfo.fBPInfo}, eventInfo.fBPTargetContexts, eventInfo.fRequestMonitor); + break; + case MODIFIED: + modifyTargetBreakpoints(bp, eventInfo.fBPTargetContexts, eventInfo.fAttributeDelta); + break; + case REMOVED: + doBreakpointsRemovedInExecutor(new IBreakpoint[]{bp}, eventInfo.fBPTargetContexts, eventInfo.fRequestMonitor); + break; + } + } } } @@ -1302,6 +1070,11 @@ if (fAttributeTranslator2 != null) { fAttributeTranslator2.updateBreakpointsStatus(eventBPs, eventType); } + else + for (IBreakpoint bp : eventBPs.keySet()) { + fAttributeTranslator.updateBreakpointStatus(bp); + } + return Status.OK_STATUS; }; diff -r 05ea843f7d56 -r 09f3d307f081 cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslatorExtension.java --- a/cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslatorExtension.java Tue Nov 17 14:33:45 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslatorExtension.java Mon Nov 23 00:59:16 2009 -0600 @@ -7,6 +7,7 @@ * * Contributors: * Wind River Systems - initial API and implementation + * Nokia - enhanced to work for both GDB and EDC. Nov. 2009. *******************************************************************************/ package org.eclipse.cdt.dsf.debug.service; @@ -14,7 +15,6 @@ import java.util.Map; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; -import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor; import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator.BreakpointEventType; import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator.ITargetBreakpointInfo; import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; @@ -22,59 +22,93 @@ import org.eclipse.debug.core.model.IBreakpoint; /** - * Breakpoint attribute translator interface + * Enhanced breakpoint attribute translator interface * * @since 2.1 */ -@ThreadSafeAndProhibitedFromDsfExecutor("") public interface IBreakpointAttributeTranslatorExtension extends IBreakpointAttributeTranslator { /** - * Convert all attributes of the given platform breakpoint (BP) to - * attributes of potential target breakpoints. Two tasks are involved:
- * 1. Convert the attributes to debugger specific ones, if needed. For - * instance, GDB implementation has its own breakpoint attribute keys.
- * 2. Resolve the breakpoint. A platform BP may be mapped to two or more - * target BPs, e.g. a breakpoint in an in-line function may be mapped to - * several target BPs, or a thread-specific BP may be mapped to several - * target BPs each of which is for one thread. This method will return an - * attribute map for each of the target BP.
+ * Resolve the breakpoint in given context. A platform BP may be mapped to + * two or more target BPs, e.g. a breakpoint in an in-line function may be + * mapped to several target BPs, or a thread-specific BP may be mapped to + * several target BPs each of which is for one thread. This method will get + * the list of attribute maps each of which corresponds to one target BP.
*
- * This method must be called in DSF execution thread. + * This method is and must be called in DSF execution thread. * * @param context * - a IBreakpointsTargetDMContext object (which could be a * process or a loaded module) in which we locate target BPs for - * the platform BP. + * the platform BP. Cannot be null. * @param breakpoint * - platform breakpoint. - * @param bpManagerEnabled - * - flag from platform breakpoint manager indicating that all - * breakpoints are enabled. + * @param bpAttributes + * - all attributes of the breakpoint, usually output from + * {@link #getAllBreakpointAttributes(IBreakpoint, boolean)}. * @param drm * - on completion of the request, the DataRequestMonitor * contains one or more attribute maps each of which * corresponding to one target breakpoint. * @throws CoreException */ - public void getTargetBreakpointAttributes(IBreakpointsTargetDMContext context, IBreakpoint breakpoint, - boolean bpManagerEnabled, DataRequestMonitor>> drm); + public void resolveBreakpoint(IBreakpointsTargetDMContext context, IBreakpoint breakpoint, + Map bpAttributes, DataRequestMonitor>> drm); - /** - * Convert platform breakpoint attributes to target-recognizable attributes. - * This method does not perform task #2 done by {@link this#getTargetBreakpointAttributes(List, IBreakpoint, boolean)}. - * - * @param platformBPAttrDelta - * @return - */ - public Map convertAttributeDelta(Map platformBPAttrDelta); + /** + * Get all platform defined attributes for a breakpoint plus all attributes + * defined by any breakpoint extension such as ICBreakpointExtension in CDT. + * In other words, get all attributes available from UI.
+ *
+ * The attributes returned are independent of runtime context (process, + * module, etc), whereas attributes from + * {@link #resolveBreakpoint(IBreakpointsTargetDMContext, IBreakpoint, Map, DataRequestMonitor)} + * are context sensitive.
+ *
+ * Note this method must not be called in DSF dispatch thread because we are + * accessing the resources system to retrieve the breakpoint attributes. + * Accessing the resources system potentially requires using global locks. + * + * @param platformBP + * @param bpManagerEnabled + * @return list of target (debugger implementation) recognizable attributes. + * @throws CoreException + */ + public Map getAllBreakpointAttributes(IBreakpoint platformBP, boolean bpManagerEnabled) throws CoreException; + + /** + * Convert platform breakpoint attributes to target attributes. This usually + * involves changing attributes keys to target recognizable ones. For + * instance, GDB integration has its own breakpoint attribute keys.
+ * + * @param platformBPAttr + * @return + */ + public Map convertAttributes(Map platformBPAttr); /** * Update platform about breakpoint status change, e.g. breakpoint installed on target successfully or breakpoint - * removed from target successfully. - * + * removed from target successfully.
+ *
+ * Note this method is not and must not be called in DSF dispatch thread. + * * @param bpsInfo * @param eventType */ public void updateBreakpointsStatus(Map> bpsInfo, BreakpointEventType eventType); + + /** + * This is enhanced version of + * {@link #canUpdateAttributes(org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext, Map)} + * in that this API gives more context parameters so that client can make + * decision on a finer granularity when needed.
+ *
+ * This will be called in DSF dispatch thread. + * + * @param bp platform breakpoint. + * @param context + * @param attributes target-recognizable attributes. + * @return false as long as one of the attributes cannot be updated by client, otherwise true. + */ + public boolean canUpdateAttributes(IBreakpoint bp, IBreakpointsTargetDMContext context, Map attributes); } \ No newline at end of file