# HG changeset patch # User Ed Swartz # Date 1259958775 21600 # Node ID e120fb809ed2ea72e250a1beac7fa6150c25298a # Parent 71e3840b8ecaded9132c855244e036ad751116de# Parent d94b9ba55bedc099e07649fb1db8182aa782b3dc Merge commit diff -r 71e3840b8eca -r e120fb809ed2 cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointAttributeTranslator.java --- a/cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointAttributeTranslator.java Fri Dec 04 14:31:59 2009 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,561 +0,0 @@ -/******************************************************************************* - * 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 71e3840b8eca -r e120fb809ed2 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 Fri Dec 04 14:31:59 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java Fri Dec 04 14:32:55 2009 -0600 @@ -15,8 +15,6 @@ 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; @@ -29,8 +27,6 @@ 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; @@ -39,9 +35,7 @@ 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; @@ -49,11 +43,8 @@ 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; /** @@ -290,53 +281,6 @@ 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 /////////////////////////////////////////////////////////////////////////// @@ -819,7 +763,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; - final IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); + IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); final Map contextBreakpoints = fBreakpoints.get(context); final int reference = breakpointCtx.getReference(); MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); @@ -838,22 +782,11 @@ // Determine if the breakpoint condition changed String conditionAttribute = CONDITION; if (properties.containsKey(conditionAttribute)) { - final String oldValue = breakpoint.getCondition(); + String oldValue = breakpoint.getCondition(); String newValue = (String) properties.get(conditionAttribute); if (newValue == null) newValue = NULL_STRING; if (!oldValue.equals(newValue)) { - 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(); - }}); + changeCondition(context, reference, newValue, countingRm); numberOfChanges++; } properties.remove(conditionAttribute); @@ -892,26 +825,6 @@ 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 71e3840b8eca -r e120fb809ed2 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 Fri Dec 04 14:31:59 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsManager.java Fri Dec 04 14:32:55 2009 -0600 @@ -15,8 +15,74 @@ package org.eclipse.cdt.dsf.mi.service; -import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator; +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.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 @@ -24,8 +90,107 @@ * * It relies on MIBreakpoints for the actual back-end interface. */ -public class MIBreakpointsManager extends BreakpointsMediator +public class MIBreakpointsManager extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener { + // 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 @@ -35,6 +200,1515 @@ * @param debugModelId the debugging model */ public MIBreakpointsManager(DsfSession session, String debugModelId) { - super(session, new MIBreakpointAttributeTranslator(session, 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()); + } } + + /** + * 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 71e3840b8eca -r e120fb809ed2 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 Fri Dec 04 14:31:59 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java Fri Dec 04 14:32:55 2009 -0600 @@ -7,14 +7,12 @@ * * Contributors: * Wind River - Initial API and implementation - * Ericsson - Low-level breakpoints integration - * Nokia - refactored to work for both GDB and EDC. Nov. 2009. + * Ericsson - Low-level breakpoints integration *******************************************************************************/ package org.eclipse.cdt.dsf.debug.service; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -27,9 +25,9 @@ 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.IDsfStatusConstants; 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.IBreakpointDMContext; import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; @@ -43,177 +41,76 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; 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.IBreakpointsListener; import org.eclipse.debug.core.model.IBreakpoint; 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 +public class BreakpointsMediator extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener { - public enum BreakpointEventType {ADDED, REMOVED, MODIFIED}; - + /** * The attribute translator that this service will use to map the platform - * breakpoint attributes to the corresponding target attributes, and vice + * breakpiont attributes to the corresponding target attributes, and vice * versa. */ private IBreakpointAttributeTranslator fAttributeTranslator; - - /** - * If the attribute translator implements the {@link IBreakpointAttributeTranslatorExtension}, - * this field will be valid, otherwise it is null. - */ - private IBreakpointAttributeTranslatorExtension fAttributeTranslator2; /** * DSF Debug service for creating breakpoints. */ - IBreakpoints fBreakpointsService; + IBreakpoints fBreakpoints; /** * Platform breakpoint manager */ IBreakpointManager fBreakpointManager; - - /** - * Object describing the information about a single target breakpoint - * corresponding to specific platform breakpoint and breakpoint target - * context. - * - * @since 2.1 - */ - public interface ITargetBreakpointInfo { - - /** - * Returns the breakpoint attributes as returned by the attribute translator. - */ - public Map getAttributes(); - - /** - * Returns the target breakpoint context. May be null if the - * breakpoint failed to install on target. - */ - public IBreakpointDMContext getTargetBreakpoint(); - - /** - * Returns the status result of the last breakpoint operation (install/remove). - */ - public IStatus getStatus(); - } + - private static class TargetBP implements ITargetBreakpointInfo { - - private Map fAttributes; - private IBreakpointDMContext fTargetBPContext; - private IStatus fStatus; - - public TargetBP(Map attrs) { - fAttributes = attrs; - } - - public Map getAttributes() { - return fAttributes; - } - - public IBreakpointDMContext getTargetBreakpoint() { - return fTargetBPContext; - } - - public IStatus getStatus() { - return fStatus; - } - - public void setTargetBreakpoint(IBreakpointDMContext fTargetBPContext) { - this.fTargetBPContext = fTargetBPContext; - } - - public void setStatus(IStatus status) { - this.fStatus = status; - } - } - - 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 /////////////////////////////////////////////////////////////////////////// /** - * Holds the set of platform breakpoints with their breakpoint information - * structures, per context (i.e. each platform breakpoint is + * 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>>(); + 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; - } + /** + * 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>> fBreakpointDMContexts = + new HashMap>>(); - 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 * is used to store requests until the ongoing operation completes. */ - private Set fRunningEvents = new HashSet(); - - private Map> fPendingEvents = - new HashMap>(); + private Set fPendingRequests = new HashSet(); + + /** + * @see fPendingRequests + */ + private Set fPendingBreakpoints = new HashSet(); /////////////////////////////////////////////////////////////////////////// // AbstractDsfService @@ -228,10 +125,6 @@ public BreakpointsMediator(DsfSession session, IBreakpointAttributeTranslator attributeTranslator) { super(session); fAttributeTranslator = attributeTranslator; - - fAttributeTranslator2 = null; - if (attributeTranslator instanceof IBreakpointAttributeTranslatorExtension) - fAttributeTranslator2 = (IBreakpointAttributeTranslatorExtension)attributeTranslator; } @Override @@ -256,7 +149,7 @@ private void doInitialize(RequestMonitor rm) { // Get the services references - fBreakpointsService = getServicesTracker().getService(IBreakpoints.class); + fBreakpoints = getServicesTracker().getService(IBreakpoints.class); fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager(); fAttributeTranslator.initialize(this); @@ -324,12 +217,20 @@ * @param dmc Context to start tracking breakpoints for. * @param rm Completion callback. */ - public void startTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { + public void startTrackingBreakpoints(IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { // - Augment the maps with the new execution context // - Install the platform breakpoints on the selected target + + // Validate the context + final IBreakpointsTargetDMContext breakpointsDmc = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); + if (breakpointsDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context type", null)); //$NON-NLS-1$ + rm.done(); + return; + } // Make sure a mapping for this execution context does not already exist - Map> platformBPs = fPlatformBPs.get(dmc); + Map>> platformBPs = fPlatformBPs.get(dmc); if (platformBPs != null) { rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Context already initialized", null)); //$NON-NLS-1$ rm.done(); @@ -338,7 +239,8 @@ // 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>()); + fPlatformBPs.put(breakpointsDmc, new HashMap>>()); + fBreakpointDMContexts.put(breakpointsDmc, new HashMap>()); // Install the platform breakpoints (stored in fPlatformBPs) on the target. // We need to use a background thread for this operation because we are @@ -346,142 +248,165 @@ // Accessing the resources system potentially requires using global locks. // Also we will be calling IBreakpointAttributeTranslator which is prohibited // from being called on the session executor thread. - new Job("Install initial breakpoint list.") { //$NON-NLS-1$ - { setSystem(true); } - - // Get the stored breakpoints from the platform BreakpointManager - // and install them on the target - @Override - protected IStatus run(IProgressMonitor monitor) { - doBreakpointsAdded(DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(), dmc, rm); - return Status.OK_STATUS; - } - }.schedule(); - } - - public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { - // - Remove the target breakpoints for the given execution context - // - Update the maps - - // Remove the breakpoints for given DMC from the internal maps. - Map> platformBPs = fPlatformBPs.get(dmc); - 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$ + new Job("MI Debugger: Install initial breakpoint list.") { //$NON-NLS-1$ { setSystem(true); } // Get the stored breakpoints from the platform BreakpointManager // and install them on the target @Override protected IStatus run(IProgressMonitor monitor) { - doBreakpointsRemoved(bps, dmc, rm); + // Read initial breakpoints from platform. Copy the breakpoint attributes into a local map. + // Note that we cannot write data into fPlatformBPs table here directly because we are not + // executing on the dispatch thread. + final Map>> initialPlatformBPs = + new HashMap>>(); + try { + // Get the stored breakpoint list from the platform BreakpointManager + IBreakpoint[] bps = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(); + // Single out the installable breakpoints... + for (IBreakpoint bp : bps) { + if (fAttributeTranslator.supportsBreakpoint(bp)) { + // Retrieve the breakpoint attributes + List> attrsArray = + fAttributeTranslator.getBreakpointAttributes(bp, fBreakpointManager.isEnabled()); + // Store it for now (will be installed on the dispatcher thread) + initialPlatformBPs.put(bp, attrsArray); + } + } + } catch (CoreException e) { + IStatus status = new Status( + IStatus.ERROR, DsfPlugin.PLUGIN_ID, REQUEST_FAILED, "Unable to read initial breakpoint attributes", e); //$NON-NLS-1$ + rm.setStatus(status); + rm.done(); + return status; + } + + // Submit the runnable to plant the breakpoints on dispatch thread. + getExecutor().submit(new Runnable() { + public void run() { + installInitialBreakpoints(breakpointsDmc, initialPlatformBPs, rm); + } + }); + return Status.OK_STATUS; } }.schedule(); } - - /** - * Find target breakpoints installed in the given context that are resolved - * from the given platform breakpoint. - * - * @param dmc - context - * @param platformBp - platform breakpoint - * @return array of target breakpoints. - */ - public ITargetBreakpointInfo[] getTargetBreakpoints(IBreakpointsTargetDMContext dmc, IBreakpoint platformBp) { - assert getExecutor().isInExecutorThread(); - - Map> platformBPs = fPlatformBPs.get(dmc); - if (platformBPs != null) - { - List bpInfo = platformBPs.get(platformBp); - if (bpInfo != null) { - return bpInfo.toArray(new ITargetBreakpointInfo[bpInfo.size()]); - } - } - return null; - } - /** - * Find the platform breakpoint that's mapped to the given target breakpoint. - * - * @param dmc - context of the target breakpoint, can be null. - * @param bp - target breakpoint - * @return platform breakpoint. null if not found. + * Installs the breakpoints that existed prior to the activation of this + * breakpoints context. */ - public IBreakpoint getPlatformBreakpoint(IBreakpointsTargetDMContext dmc, IBreakpointDMContext bp) { - assert getExecutor().isInExecutorThread(); + private void installInitialBreakpoints(final IBreakpointsTargetDMContext dmc, + Map>> initialPlatformBPs, + RequestMonitor rm) + { + // Retrieve the set of platform breakpoints for this context + Map>> platformBPs = fPlatformBPs.get(dmc); + if (platformBPs == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Install the individual breakpoints on the executor thread + // Requires a counting monitor to know when we're done + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm); + countingRm.setDoneCount(initialPlatformBPs.size()); + + for (final IBreakpoint bp : initialPlatformBPs.keySet()) { + final List> attrs = initialPlatformBPs.get(bp); + // Upon determining the debuggerPath, the breakpoint is installed + installBreakpoint(dmc, bp, attrs, new RequestMonitor(getExecutor(), countingRm)); + } + } + + + public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { + // - Remove the target breakpoints for the given execution context + // - Update the maps - for (IBreakpointsTargetDMContext bpContext : fPlatformBPs.keySet()) { - if (dmc != null && !dmc.equals(bpContext)) - continue; - - Map> platformBPs = fPlatformBPs.get(bpContext); - - if (platformBPs != null && platformBPs.size() > 0) - { - for(Map.Entry> e: platformBPs.entrySet()) - { - // Stop at the first occurrence - for (TargetBP tbp : e.getValue()) - if(tbp.getTargetBreakpoint().equals(bp)) - return e.getKey(); - } - } - } + // 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$ + rm.done(); + return; + } + + // Uninstall the individual breakpoints on the executor thread + // Requires a counting monitor to know when we're done + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm); + countingRm.setDoneCount(platformBPs.size()); - return null; + for (final IBreakpoint bp : platformBPs.keySet()) { + uninstallBreakpoint(dmc, bp, + new RequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleCompleted() { + // After the breakpoint is removed from target. Call the attribute + // translator to refresh breakpoint status based on the new target + // breakpoint status. + new Job("Breakpoint status update") { //$NON-NLS-1$ + { setSystem(true); } + @Override + protected IStatus run(IProgressMonitor monitor) { + fAttributeTranslator.updateBreakpointStatus(bp); + return Status.OK_STATUS; + }; + }.schedule(); + + countingRm.done(); + } + }); + } } - + /////////////////////////////////////////////////////////////////////////// // Back-end interface functions /////////////////////////////////////////////////////////////////////////// /** * Install a new platform breakpoint on the back-end. A platform breakpoint - * can resolve into multiple back-end breakpoints, e.g. when threads are taken + * can resolve into multiple back-end breakpoints when threads are taken * into account. * * @param dmc * @param breakpoint - * @param attrsList - list of attribute map, each mapping to a potential target BP. + * @param attrsList * @param rm */ private void installBreakpoint(IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint, - final List> attrsList, final DataRequestMonitor> rm) + final List> attrsList, final RequestMonitor rm) { // Retrieve the set of breakpoints for this context - final Map> platformBPs = fPlatformBPs.get(dmc); + final Map>> platformBPs = fPlatformBPs.get(dmc); assert platformBPs != null; + final Map> breakpointIDs = fBreakpointDMContexts.get(dmc); + assert breakpointIDs != null; // fBreakpointIds should be updated in parallel with fPlatformBPs + // Ensure the breakpoint is not already installed - assert !platformBPs.containsKey(breakpoint); - - final ArrayList targetBPsAttempted = new ArrayList(attrsList.size()); - for (int i = 0; i < attrsList.size(); i++) { - targetBPsAttempted.add(new TargetBP(attrsList.get(i))); + if (platformBPs.containsKey(breakpoint)) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_STATE, "Breakpoint already installed", null)); //$NON-NLS-1$ + rm.done(); + return; } - - final ArrayList targetBPsInstalled = new ArrayList(attrsList.size()); // Update the breakpoint status when all back-end breakpoints have been installed final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), rm) { @Override protected void handleCompleted() { - // Store successful targetBPs with the platform breakpoint - if (targetBPsInstalled.size() > 0) - platformBPs.put(breakpoint, targetBPsInstalled); - - // Store all targetBPs, success or failure, in the rm. - rm.setData(targetBPsAttempted); + // Store the platform breakpoint + platformBPs.put(breakpoint, attrsList); + new Job("Breakpoint status update") { //$NON-NLS-1$ + { setSystem(true); } + @Override + protected IStatus run(IProgressMonitor monitor) { + fAttributeTranslator.updateBreakpointStatus(breakpoint); + return Status.OK_STATUS; + }; + }.schedule(); rm.done(); } }; @@ -490,22 +415,25 @@ installRM.setDoneCount(attrsList.size()); // Install the back-end breakpoint(s) - for (int _i = 0; _i < attrsList.size(); _i++) { - final int i = _i; - fBreakpointsService.insertBreakpoint( - dmc, attrsList.get(i), + for (Map attrs : attrsList) { + fBreakpoints.insertBreakpoint( + dmc, attrs, new DataRequestMonitor(getExecutor(), installRM) { @Override protected void handleCompleted() { - TargetBP targetBP = targetBPsAttempted.get(i); + List list = breakpointIDs.get(breakpoint); + if (list == null) { + list = new LinkedList(); + breakpointIDs.put(breakpoint, list); + } + if (isSuccess()) { // Add the breakpoint back-end mapping - targetBP.setTargetBreakpoint(getData()); - - targetBPsInstalled.add(targetBP); - } - targetBP.setStatus(getStatus()); - + list.add(getData()); + } else { + // TODO (bug 219841): need to add breakpoint error status tracking + // in addition to fBreakpointDMContexts. + } installRM.done(); } }); @@ -518,612 +446,441 @@ * * @param dmc * @param breakpoint - * @param drm + * @param rm */ private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint, - final DataRequestMonitor> drm) + final RequestMonitor rm) { + // Remove completion monitor + CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + // Remove the attributes mapping + Map>> platformBPs = fPlatformBPs.get(dmc); + if (platformBPs == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + platformBPs.remove(breakpoint); + + // Remove the back-end mapping + Map> breakpointIDs = fBreakpointDMContexts.get(dmc); + if (breakpointIDs == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$ + rm.done(); + return; + } + breakpointIDs.get(breakpoint).clear(); + breakpointIDs.remove(breakpoint); + + // Update breakpoint status + new Job("Breakpoint status update") { //$NON-NLS-1$ + { setSystem(true); } + @Override + protected IStatus run(IProgressMonitor monitor) { + fAttributeTranslator.updateBreakpointStatus(breakpoint); + return Status.OK_STATUS; + }; + }.schedule(); + + rm.done(); + } + }; + // Remove the back-end breakpoints - final Map> platformBPs = fPlatformBPs.get(dmc); - if (platformBPs == null) { - drm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$ - drm.done(); + Map> breakpointIDs = fBreakpointDMContexts.get(dmc); + if (breakpointIDs == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + List list = breakpointIDs.get(breakpoint); + int count = 0; + if (list != null) { + for (IBreakpointDMContext bp : list) { + fBreakpoints.removeBreakpoint(bp, removeRM); + } + count = list.size(); + } + removeRM.setDoneCount(count); + } + + /** + * Modify an individual breakpoint + * + * @param context + * @param breakpoint + * @param attributes + * @param rm + * @throws CoreException + */ + private void modifyBreakpoint(final IBreakpointsTargetDMContext context, final IBreakpoint breakpoint, + final List> newAttrsList0, final IMarkerDelta oldValues, final RequestMonitor rm) + { + // 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); + final Map> breakpointIDs = fBreakpointDMContexts.get(context); + if (platformBPs == null || breakpointIDs == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Get the original breakpoint attributes + final List> oldAttrsList0 = platformBPs.get(breakpoint); + if (oldAttrsList0 == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Get the list of corresponding back-end breakpoints + final List oldBpContexts = new ArrayList(breakpointIDs.get(breakpoint)); + if (oldBpContexts == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$ + rm.done(); return; } - final List bpList = platformBPs.get(breakpoint); - assert bpList != null; - - // Only try to remove those targetBPs that are successfully installed. - - // Remove completion monitor - final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), drm) { - @Override - protected void handleCompleted() { - platformBPs.remove(breakpoint); - - // Complete the request monitor. - drm.setData(bpList); - drm.done(); - } - }; + // Calculate the list of attributes maps that have not changed. + // Immediately add these to the list of new breakpoint contexts, + // and remove them from further breakpoint attribute comparisons. + final List> commonAttrsList = getCommonAttributeMaps(newAttrsList0, oldAttrsList0); + final List newBpContexts = new ArrayList(commonAttrsList.size()); - int count = 0; - for (int i = 0; i < bpList.size(); i++) { - final TargetBP bp = bpList.get(i); - if (bp.getTargetBreakpoint() != null) { - fBreakpointsService.removeBreakpoint( - bp.getTargetBreakpoint(), - new RequestMonitor(getExecutor(), countingRm) { - @Override - protected void handleCompleted() { - bp.setStatus(getStatus()); - if (isSuccess()) { - bp.setTargetBreakpoint(null); - } - countingRm.done(); - } - }); - count++; - } else { - bp.setStatus(Status.OK_STATUS); - } + final List> newAttrsList = new ArrayList>(newAttrsList0); + newAttrsList.removeAll(commonAttrsList); + + List> oldAttrsList = new ArrayList>(oldAttrsList0); + for (int i = 0; i < oldAttrsList.size(); i++) { + if (commonAttrsList.contains(oldAttrsList.get(i))) { + if (oldBpContexts.size() > i) { + newBpContexts.add(oldBpContexts.remove(i)); + } + } } - countingRm.setDoneCount(count); - } + oldAttrsList.removeAll(commonAttrsList); + + // Create a list of attribute changes. The lenghth of this list will + // always be max(oldAttrList.size(), newAttrsList.size()), padded with + // null's if oldAttrsList was longer. + final List> attrDeltasList = getAttributesDeltas(oldAttrsList, newAttrsList); + + // Create the request monitor that will be called when all + // modifying/inserting/removing is complete. + final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + // Save the new list of breakpoint contexts and attributes + breakpointIDs.put(breakpoint, newBpContexts); + newAttrsList.addAll(commonAttrsList); + platformBPs.put(breakpoint, newAttrsList); + + // Update breakpoint status. updateBreakpointStatus() cannot + // be called on the executor thread, so we need to + // use a Job. + new Job("Breakpoint status update") { //$NON-NLS-1$ + { setSystem(true); } + @Override + protected IStatus run(IProgressMonitor monitor) { + fAttributeTranslator.updateBreakpointStatus(breakpoint); + return Status.OK_STATUS; + }; + }.schedule(); + + super.handleCompleted(); + } + }; + + // Set the count, if could be zero if no breakpoints have actually changed. + countingRM.setDoneCount(attrDeltasList.size()); + + // Process the changed breakpoints. + for (int i = 0; i < attrDeltasList.size(); i++) { + if (attrDeltasList.get(i) == null) { + // The list of new attribute maps was shorter than the old. + // Remove the corresponding target-side bp. + fBreakpoints.removeBreakpoint(oldBpContexts.get(i), countingRM); + } else if ( i >= oldBpContexts.size()) { + // 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 handleSuccess() { + newBpContexts.add(getData()); + countingRM.done(); + } + }); + } else if ( !fAttributeTranslator.canUpdateAttributes(oldBpContexts.get(i), attrDeltasList.get(i)) ) { + // 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. + final Map attrs = newAttrsList.get(i); + fBreakpoints.removeBreakpoint( + oldBpContexts.get(i), + new RequestMonitor(getExecutor(), countingRM) { + @Override + protected void handleCompleted() { + fBreakpoints.insertBreakpoint( + context, attrs, + new DataRequestMonitor(getExecutor(), countingRM) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + newBpContexts.add(getData()); + } else { + // TODO (bug 219841): need to add breakpoint error status tracking + // in addition to fBreakpointDMContexts. + } + countingRM.done(); + } + }); + } + }); + } else { + // The back end can modify the breakpoint. Update the breakpoint with the + // new attributes. + final IBreakpointDMContext bpCtx = oldBpContexts.get(i); + fBreakpoints.updateBreakpoint( + oldBpContexts.get(i), newAttrsList.get(i), + new RequestMonitor(getExecutor(), countingRM) { + @Override + protected void handleSuccess() { + newBpContexts.add(bpCtx); + countingRM.done(); + } + }); + } + } + } + private List> getCommonAttributeMaps(List> array1, List> array2) + { + List> intersection = new LinkedList>(); + List> list2 = new ArrayList>(array2); + for (Map array1Map : array1) { + if (list2.remove(array1Map)) { + intersection.add(array1Map); + } + } + return intersection; + } + + /** + * Determine the set of modified attributes + * + * @param oldAttributes + * @param newAttributes + * @return + */ + private List> getAttributesDeltas(List> oldAttributesList, List> newAttributesList) { + List> deltas = new ArrayList>(oldAttributesList.size()); + + // Go through the bp attributes common to the old and the new lists and calculate + // their deltas. + for (int i = 0; i < oldAttributesList.size() && i < newAttributesList.size(); i++) { + Map oldAttributes = oldAttributesList.get(i); + Map newAttributes = newAttributesList.get(i); + + 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); + } + deltas.add(delta); + } + + // Add all the new attributes as deltas + for (int i = deltas.size(); i < newAttributesList.size(); i++) { + deltas.add(newAttributesList.get(i)); + } + + // For any old attribute Maps that were removed, insert a null value in the deltas list. + for (int i = deltas.size(); i < oldAttributesList.size(); i++) { + deltas.add(null); + } + + return deltas; + } + /////////////////////////////////////////////////////////////////////////// // IBreakpointManagerListener implementation /////////////////////////////////////////////////////////////////////////// public void breakpointManagerEnablementChanged(boolean enabled) { - // do nothing. breakpointsChanged() will be called to handle the change. + for (IBreakpoint breakpoint : fBreakpointManager.getBreakpoints()) { + breakpointChanged(breakpoint, null); + } } @ThreadSafe - public void breakpointsAdded(final IBreakpoint[] bps) { - doBreakpointsAdded(bps, null, null); - } - - 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 (bpsInfo.length == 0) { - if (rm != null) { - rm.done(); - } - return; - } - - try { - getExecutor().execute(new DsfRunnable() { - public void run() { - Collection dmcs = new ArrayList(); - if (bpsTargetDmc == null) - dmcs.addAll(fPlatformBPs.keySet()); - else - dmcs.add(bpsTargetDmc); + public void breakpointAdded(final IBreakpoint breakpoint) { + if (fAttributeTranslator.supportsBreakpoint(breakpoint)) { + try { + // Retrieve the breakpoint attributes + final List> attrsArray = + fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled()); - doBreakpointsAddedInExecutor(bpsInfo, dmcs, 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$ - if (rm != null) { - rm.setStatus(status); - rm.done(); - } else { - DsfPlugin.getDefault().getLog().log(status); - } - } - } - - /** - * 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)) { - 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()); - } + getExecutor().execute(new DsfRunnable() { + public void run() { + //TODO pp: need to track pending requests + + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { + @Override + protected void handleError() { + if (getStatus().getSeverity() == IStatus.ERROR) { + DsfPlugin.getDefault().getLog().log(getStatus()); + } + } + }; + countingRm.setDoneCount(fPlatformBPs.size()); + + // Install the breakpoint in all the execution contexts + for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { + installBreakpoint(dmc, breakpoint, attrsArray, new RequestMonitor(getExecutor(), countingRm)); + } + } + }); + } catch (CoreException e) { + DsfPlugin.getDefault().getLog().log(e.getStatus()); + } catch (RejectedExecutionException e) { } } - - return bpsInfo.toArray(new PlatformBreakpointInfo[bpsInfo.size()]); - } - protected void doBreakpointsAddedInExecutor(PlatformBreakpointInfo[] bpsInfo, Collection bpTargetDMCs, final RequestMonitor rm) { - final Map> eventBPs = - new HashMap>(bpsInfo.length, 1); - - CountingRequestMonitor processPendingCountingRm = new CountingRequestMonitor(getExecutor(), rm) { - @Override - protected void handleCompleted() { - processPendingRequests(); - fireUpdateBreakpointsStatus(eventBPs, BreakpointEventType.ADDED); - if (rm != null) - // don't call this if "rm" is null as this will - // log errors if any and pack Eclipse error - // log view with errors useless to user. - 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; - } - } - - // 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); } + + /////////////////////////////////////////////////////////////////////////// + // IBreakpointListener implementation + /////////////////////////////////////////////////////////////////////////// - /* - * 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; - - final PlatformBreakpointInfo[] bpsInfo = collectBreakpointsInfo(bps); - - if (bpsInfo.length == 0) - return; // nothing to do - - try { - getExecutor().execute( new DsfRunnable() { - public void run() { - Map tmp = new HashMap(1); - tmp.put(IBreakpoint.ENABLED, true); - final String targetEnablementKey = fAttributeTranslator2.convertAttributes(tmp).keySet().iterator().next(); + public void breakpointChanged(final IBreakpoint breakpoint, final IMarkerDelta delta) { + if (fAttributeTranslator.supportsBreakpoint(breakpoint)) { + try { + // Retrieve the breakpoint attributes + final List> attrsArray = + fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled()); + + // Modify the breakpoint in all the target contexts + getExecutor().execute( new DsfRunnable() { + public void run() { - 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; + // 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) { + DsfPlugin.getDefault().getLog().log(getStatus()); + } + } - 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}; + // Indicate that the pending request has completed + fPendingRequests.remove(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); - } - } - }); - } 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$ - } + // Process the next pending update for this breakpoint + if (fPendingBreakpoints.contains(breakpoint)) { + fPendingBreakpoints.remove(breakpoint); + new Job("Deferred breakpoint changed job") { //$NON-NLS-1$ + { setSystem(true); } + @Override + protected IStatus run(IProgressMonitor monitor) { + breakpointChanged(breakpoint, delta); + return Status.OK_STATUS; + }; + }.schedule(); + } + } + }; + 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()) { + modifyBreakpoint(dmc, breakpoint, attrsArray, delta, new RequestMonitor(getExecutor(), countingRm)); + } + } + }); + } catch (CoreException e) { + DsfPlugin.getDefault().getLog().log(e.getStatus()); + } catch (RejectedExecutionException e) { + } + } } - /** - * 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 updateContexts - * target contexts in which to do the modification. - * @param targetAttrDelta - * target-recognizable attribute(s) with new values. - */ - 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; + public void breakpointRemoved(final IBreakpoint breakpoint, IMarkerDelta delta) { + + if (fAttributeTranslator.supportsBreakpoint(breakpoint)) { + try { + getExecutor().execute(new DsfRunnable() { + public void run() { + //TODO pp: need to track pending requests + + CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { + @Override + protected void handleError() { + if (getStatus().getSeverity() == IStatus.ERROR) { + DsfPlugin.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).remove(breakpoint) != null) { + uninstallBreakpoint(dmc, breakpoint, countingRm); + } else { + // Breakpoint not installed for given context, do nothing. + } + } + } + }); + } catch (RejectedExecutionException e) { + } } - 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); - } - - protected void doBreakpointsRemoved(final IBreakpoint[] bps, final IBreakpointsTargetDMContext bpsTargetDmc, final RequestMonitor rm) { - - final List bpCandidates = new ArrayList(); - - for (int i = 0; i < bps.length; i++) { - IBreakpoint bp = bps[i]; - - if (fAttributeTranslator.supportsBreakpoint(bp)) { - bpCandidates.add(bp); - } - } - - if (bpCandidates.isEmpty()) { // nothing to do - if (rm != null) - rm.done(); - return; - } - - try { - getExecutor().execute(new DsfRunnable() { - public void run() { - Collection contexts = new ArrayList(); - if (bpsTargetDmc == null) - contexts.addAll(fPlatformBPs.keySet()); - else - contexts.add(bpsTargetDmc); - - 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$ - if (rm != null) { - rm.setStatus(status); - rm.done(); - } else { - DsfPlugin.getDefault().getLog().log(status); - } - } - } - - protected void doBreakpointsRemovedInExecutor(IBreakpoint[] bpCandidates, - Collection targetContexts, final 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); - if (rm != null) - // don't call this if "rm" is null as this will - // log errors if any and pack Eclipse error - // log view with errors useless to user. - 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) { - pendingEventsList = new LinkedList(); - fPendingEvents.put(breakpoint, pendingEventsList); - } - if (pendingEventsList.size() > 0 && - pendingEventsList.getLast().fEventType == BreakpointEventType.MODIFIED) { - pendingEventsList.removeLast(); - } - pendingEventsList.add(pendingEvent); - } - - 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 - - // Make a copy to avoid ConcurrentModificationException - // as we are deleting element in the loop. - Set bpsInPendingEvents = new HashSet(fPendingEvents.keySet()); - for (IBreakpoint bp : bpsInPendingEvents) { - if (! fRunningEvents.contains(bp)) { - LinkedList eventInfoList = fPendingEvents.get(bp); - - // 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; - } - } - } - } - - private void fireUpdateBreakpointsStatus(final Map> eventBPs, final BreakpointEventType eventType) { - // Update breakpoint status - new Job("Breakpoint status update") { //$NON-NLS-1$ - { setSystem(true); } - @Override - protected IStatus run(IProgressMonitor monitor) { - for (IBreakpoint bp : eventBPs.keySet()) { - fAttributeTranslator.updateBreakpointStatus(bp); - } - - if (fAttributeTranslator2 != null) { - fAttributeTranslator2.updateBreakpointsStatus(eventBPs, eventType); - } - else - for (IBreakpoint bp : eventBPs.keySet()) { - fAttributeTranslator.updateBreakpointStatus(bp); - } - - - return Status.OK_STATUS; - }; - }.schedule(); - - } - - /** - * Determine the set of modified attributes. - * - * @param oldAttributes old map of attributes. - * @param newAttributes new map of attributes. - * @return new and changed attribute in the new map. May be empty indicating the two maps are equal. - */ - private Map getAttributesDelta(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 delta; - } } diff -r 71e3840b8eca -r e120fb809ed2 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 Fri Dec 04 14:31:59 2009 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 Wind River Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Wind River Systems - initial API and implementation - * Nokia - enhanced to work for both GDB and EDC. Nov. 2009. - *******************************************************************************/ -package org.eclipse.cdt.dsf.debug.service; - -import java.util.List; -import java.util.Map; - -import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; -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; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.debug.core.model.IBreakpoint; - -/** - * Enhanced breakpoint attribute translator interface - * - * @since 2.1 - */ - -public interface IBreakpointAttributeTranslatorExtension extends IBreakpointAttributeTranslator { - /** - * 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 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. Cannot be null. - * @param breakpoint - * - platform breakpoint. - * @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 resolveBreakpoint(IBreakpointsTargetDMContext context, IBreakpoint breakpoint, - Map bpAttributes, DataRequestMonitor>> drm); - - /** - * 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.
- *
- * 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 diff -r 71e3840b8eca -r e120fb809ed2 cdt/cdt_6_0_x/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java --- a/cdt/cdt_6_0_x/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java Fri Dec 04 14:31:59 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java Fri Dec 04 14:32:55 2009 -0600 @@ -75,7 +75,7 @@ // Create the breakpoint mediator and start tracking PDA breakpoints. final BreakpointsMediator bpmService = new BreakpointsMediator( - fSession, new PDABreakpointAttributeTranslator(fCommandControl.getContext())); + fSession, new PDABreakpointAttributeTranslator()); bpmService.initialize(new RequestMonitor(getExecutor(), requestMonitor) { @Override protected void handleSuccess() { diff -r 71e3840b8eca -r e120fb809ed2 cdt/cdt_6_0_x/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpointAttributeTranslator.java --- a/cdt/cdt_6_0_x/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpointAttributeTranslator.java Fri Dec 04 14:31:59 2009 -0600 +++ b/cdt/cdt_6_0_x/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpointAttributeTranslator.java Fri Dec 04 14:32:55 2009 -0600 @@ -14,15 +14,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator; import org.eclipse.cdt.dsf.debug.service.IBreakpointAttributeTranslator; -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.examples.dsf.pda.PDAPlugin; import org.eclipse.cdt.examples.dsf.pda.breakpoints.PDALineBreakpoint; import org.eclipse.cdt.examples.dsf.pda.breakpoints.PDAWatchpoint; @@ -59,18 +54,9 @@ PDAWatchpoint.MODIFICATION }; - private final IBreakpointsTargetDMContext fBreakpointsTargetDmc; - - private BreakpointsMediator fMediator; - - public PDABreakpointAttributeTranslator(IBreakpointsTargetDMContext breakpointsTargetDmc) { - fBreakpointsTargetDmc = breakpointsTargetDmc; - } - // PDA breakpoints translator doesn't keep any state and it doesn't // need to initialize or clean up. public void initialize(BreakpointsMediator mediator) { - fMediator = mediator; } public void dispose() { @@ -142,38 +128,8 @@ return bp.getModelIdentifier().equals(PDAPlugin.ID_PDA_DEBUG_MODEL); } - public void updateBreakpointStatus(final IBreakpoint bp) { - Future future = fMediator.getSession().getExecutor().submit(new Callable() { - public ITargetBreakpointInfo[] call() throws Exception { - return fMediator.getTargetBreakpoints(fBreakpointsTargetDmc, bp); - } - }); - - - ITargetBreakpointInfo[] targetBPs = null; - try { - targetBPs = future.get(); - } catch (InterruptedException e1) { - } catch (ExecutionException e1) { - assert false; - } - - try { - boolean oldInstalled = ((PDALineBreakpoint)bp).getInstalled(); - boolean newInstalled = false; - for (int i = 0; targetBPs != null && i < targetBPs.length; i++) { - if (targetBPs[i].getTargetBreakpoint() != null) { - newInstalled = true; - break; - } - } - if (oldInstalled != newInstalled) { - ((PDALineBreakpoint)bp).setInstalled(newInstalled); - } - System.out.println(bp.toString() + " installed = " + newInstalled); - } catch (CoreException e) { - // Marker access race condition: most likely the breakpoint has already been removed - } + public void updateBreakpointStatus(IBreakpoint bp) { + // PDA breakpoints do not support status reporting } } diff -r 71e3840b8eca -r e120fb809ed2 cdt/cdt_6_0_x/org.eclipse.cdt.launch/src/org/eclipse/cdt/launch/ui/CMainTab.java