/******************************************************************************* * Copyright (c) 2015, 2016 Kichwa Coders 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: * Jonah Graham (Kichwa Coders) - initial API and implementation to Add support for gdb's "set substitute-path" (Bug 472765) *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.launching; import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfExecutor; 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.debug.service.ICachingService; import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; import org.eclipse.cdt.dsf.debug.service.IStack; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.sourcelookup.DsfSourceLookupParticipant; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.service.IGDBSourceLookup; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; /** * Source Lookup Participant that notifies the {@link IGDBSourceLookup} service * of changes to the lookup path to allow the source lookup service to update * GDB's substituted paths. * * @since 5.0 */ @ThreadSafe public class GdbSourceLookupParticipant extends DsfSourceLookupParticipant { private DsfExecutor fExecutor; private String fSessionId; private DsfServicesTracker fServicesTracker; public GdbSourceLookupParticipant(DsfSession session) { super(session); fSessionId = session.getId(); fExecutor = session.getExecutor(); fServicesTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSessionId); } @Override public void init(ISourceLookupDirector director) { super.init(director); } @Override public void dispose() { fServicesTracker.dispose(); super.dispose(); } @Override public void sourceContainersChanged(final ISourceLookupDirector director) { super.sourceContainersChanged(director); /* * The change can be issued directly on the executor thread, or on other * threads, so we need to continue on the correct thread. */ if (fExecutor.isInExecutorThread()) { sourceContainersChangedOnDispatchThread(director, new RequestMonitor(fExecutor, null)); } else { /* * Don't use a Query here, this method must be non-blocking on the * calling thread as there is an interlock possible when two * executors get the same update for the same launch configuration * at the same time. See Bug 494650 for more info. */ fExecutor.execute(new DsfRunnable() { @Override public void run() { sourceContainersChangedOnDispatchThread(director, new RequestMonitor(fExecutor, null)); } }); } } @ConfinedToDsfExecutor("fExecutor") protected void sourceContainersChangedOnDispatchThread(final ISourceLookupDirector director, final RequestMonitor rm) { IGDBSourceLookup lookup = fServicesTracker.getService(IGDBSourceLookup.class); if (lookup != null) { IStack stackService = fServicesTracker.getService(IStack.class); if (stackService instanceof ICachingService) { /* * To preserve the atomicity of this method, we need to clear * the cache without waiting for * lookup.sourceContainersChanged() to report if there was * actually a change on the source containers. The cache needs * to be cleared so that any further requests to GDB (e.g. * getting stack frames) sees the new values from GDB after the * source lookup changes. This means we are over clearing the * cache, but this method is only called when the source * containers change which does not happen normally during a * debug session. * * XXX: Adding an event once we finished the update would allow * other interested parties (such as the Debug View) from being * notified that the frame data has changed. See Bug 489607. */ ICachingService cachingStackService = (ICachingService) stackService; cachingStackService.flushCache(null); } ICommandControlService command = fServicesTracker.getService(ICommandControlService.class); ISourceLookupDMContext context = (ISourceLookupDMContext) command.getContext(); lookup.sourceContainersChanged(context, new DataRequestMonitor<Boolean>(fExecutor, rm)); } else { rm.done(); } } }