mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 568228: Add a way for DSF Data Model to initiate refresh all
There is no way to predict what the user might do during for example the launch sequence, so as a last resort, tell the UI to drop all caches and refresh the data as the last step of the launch sequence. Change-Id: I97731c8286657a0fc1111ba41deb47863181a453 Also-by: Jonah Graham <jonah@kichwacoders.com> Signed-off-by: Torbjörn Svensson <azoff@svenskalinuxforeningen.se>
This commit is contained in:
parent
3ffe2156ff
commit
293998da18
9 changed files with 176 additions and 4 deletions
|
@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
|
|||
Bundle-Name: %pluginName
|
||||
Bundle-Vendor: %providerName
|
||||
Bundle-SymbolicName: org.eclipse.cdt.dsf.gdb;singleton:=true
|
||||
Bundle-Version: 6.0.100.qualifier
|
||||
Bundle-Version: 6.1.0.qualifier
|
||||
Bundle-Activator: org.eclipse.cdt.dsf.gdb.internal.GdbPlugin
|
||||
Bundle-Localization: plugin
|
||||
Require-Bundle: org.eclipse.core.runtime,
|
||||
|
|
|
@ -29,9 +29,11 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
@ -39,8 +41,11 @@ import java.util.concurrent.RejectedExecutionException;
|
|||
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
|
||||
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.datamodel.AbstractDMEvent;
|
||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.ICachingService;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRunControl;
|
||||
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
|
||||
|
@ -68,6 +73,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIResultRecord;
|
|||
import org.eclipse.cdt.dsf.mi.service.command.output.MIStreamRecord;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
|
||||
import org.eclipse.cdt.dsf.service.AbstractDsfService;
|
||||
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
|
@ -145,6 +151,16 @@ public abstract class AbstractMIControl extends AbstractDsfService implements IM
|
|||
|
||||
private CommandFactory fCommandFactory;
|
||||
|
||||
/**
|
||||
* Event indicating that the back end process has started.
|
||||
*/
|
||||
private static class RefreshAllDMEvent extends AbstractDMEvent<ICommandControlDMContext>
|
||||
implements ICommandControlRefreshAllDMEvent {
|
||||
public RefreshAllDMEvent(ICommandControlDMContext context) {
|
||||
super(context);
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractMIControl(DsfSession session) {
|
||||
this(session, false, false, new CommandFactory());
|
||||
}
|
||||
|
@ -1226,4 +1242,21 @@ public abstract class AbstractMIControl extends AbstractDsfService implements IM
|
|||
processCommandDone(commandHandle, info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 6.1
|
||||
*/
|
||||
@Override
|
||||
public void flushAllCachesAndRefresh(RequestMonitor rm) {
|
||||
DsfServicesTracker servicesTracker = getServicesTracker();
|
||||
|
||||
Set<ICachingService> services = new HashSet<>(servicesTracker.getServices(ICachingService.class));
|
||||
for (ICachingService service : services) {
|
||||
service.flushCache(null);
|
||||
}
|
||||
|
||||
// Issue a refresh event for any services or UI that is not an ICachingService
|
||||
getSession().dispatchEvent(new RefreshAllDMEvent(getContext()), getProperties());
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,21 @@ import java.util.concurrent.RejectedExecutionException;
|
|||
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRunControl;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlRefreshAllDMEvent;
|
||||
import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.ISteppingControlParticipant;
|
||||
import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.IRefreshAllTarget;
|
||||
import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
|
||||
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.IVMAdapter;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMAdapter;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
|
||||
import org.eclipse.jface.viewers.StructuredSelection;
|
||||
|
||||
/**
|
||||
* Base class for VM adapters used for implementing a debugger integration.
|
||||
|
@ -78,4 +88,34 @@ public class AbstractDebugVMAdapter extends AbstractDMVMAdapter implements IStep
|
|||
} // Do nothing if session is shut down.
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@DsfServiceEventHandler
|
||||
public void eventDispatched(ICommandControlRefreshAllDMEvent event) {
|
||||
if (isDisposed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IRefreshAllTarget refreshTarget = (IRefreshAllTarget) getSession().getModelAdapter(IRefreshAllTarget.class);
|
||||
if (refreshTarget == null) {
|
||||
return;
|
||||
}
|
||||
StructuredSelection debugContext = new StructuredSelection(new IAdaptable() {
|
||||
@Override
|
||||
public <T> T getAdapter(Class<T> adapter) {
|
||||
if (IVMAdapter.class.equals(adapter)) {
|
||||
return adapter.cast(AbstractDebugVMAdapter.this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
try {
|
||||
refreshTarget.refresh(debugContext);
|
||||
} catch (CoreException e) {
|
||||
// This is probably unreachable as the DefaultRefreshAllTarget.refresh does not
|
||||
// throw CoreException in this case.
|
||||
DsfUIPlugin.log(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID,
|
||||
"Failed to refresh following receipt of a Refresh All Event.", e)); //$NON-NLS-1$
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,4 +22,12 @@
|
|||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
<resource path="src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java" type="org.eclipse.cdt.dsf.debug.service.command.ICommandControlService">
|
||||
<filter comment="CDT allows new default methods that are unlikely to conflict" id="404000815">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.cdt.dsf.debug.service.command.ICommandControlService"/>
|
||||
<message_argument value="flushAllCachesAndRefresh(RequestMonitor)"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
</component>
|
||||
|
|
|
@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
|
|||
Bundle-Name: %pluginName
|
||||
Bundle-Vendor: %providerName
|
||||
Bundle-SymbolicName: org.eclipse.cdt.dsf;singleton:=true
|
||||
Bundle-Version: 2.9.100.qualifier
|
||||
Bundle-Version: 2.10.0.qualifier
|
||||
Bundle-Activator: org.eclipse.cdt.dsf.internal.DsfPlugin
|
||||
Bundle-Localization: plugin
|
||||
Require-Bundle: org.eclipse.core.runtime,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.debug.service.command;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
|
||||
import org.eclipse.cdt.dsf.service.IDsfService;
|
||||
|
@ -51,6 +52,13 @@ public interface ICommandControlService extends ICommandControl, IDsfService {
|
|||
public interface ICommandControlShutdownDMEvent extends IDMEvent<ICommandControlDMContext> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Event indicating that the back end has had some change that means everything should be invalidated.
|
||||
* @since 2.10
|
||||
*/
|
||||
public interface ICommandControlRefreshAllDMEvent extends IDMEvent<ICommandControlDMContext> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of this command control service. It can be used
|
||||
* to distinguish between multiple instances of command control services.
|
||||
|
@ -69,4 +77,14 @@ public interface ICommandControlService extends ICommandControl, IDsfService {
|
|||
* @return
|
||||
*/
|
||||
public boolean isActive();
|
||||
|
||||
/**
|
||||
* This method should be called when a service knows that something has changed in the
|
||||
* backend, but cannot update the state in an effective way, so the decision instead
|
||||
* is to flush all caches and refresh by issuing an {@link ICommandControlRefreshAllDMEvent}.
|
||||
* @since 2.10
|
||||
*/
|
||||
default public void flushAllCachesAndRefresh(RequestMonitor rm) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Set;
|
|||
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.cdt.dsf.debug.service.ICachingService;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Constants;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
@ -192,6 +193,13 @@ abstract public class AbstractDsfService implements IDsfService, IDsfStatusConst
|
|||
classSet.add(IDsfService.class.getName());
|
||||
classSet.add(getClass().getName());
|
||||
|
||||
/*
|
||||
* Ensure that the list of classes contains the ICachingService if implemented
|
||||
*/
|
||||
if (this instanceof ICachingService) {
|
||||
classSet.add(ICachingService.class.getName());
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the session ID is set in the service properties.
|
||||
* The session ID distinguishes this service instance from instances
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
package org.eclipse.cdt.dsf.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
|
||||
|
@ -207,7 +209,39 @@ public class DsfServicesTracker {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convenience class to retrieve a service based on class name only.
|
||||
* Retrieves all service references for given optional filter.
|
||||
* Filter should be used if there are multiple instances of the desired service
|
||||
* running within the same session.
|
||||
* @param custom filter to use when searching for the service, this filter will
|
||||
* be used instead of the standard filter so it should also specify the desired
|
||||
* session-ID
|
||||
* @return List of OSGI service references to the desired service
|
||||
* @since 2.10
|
||||
*/
|
||||
public <V> Collection<ServiceReference<V>> getServiceReferences(Class<V> serviceClass, String filter) {
|
||||
if (fDisposed) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// If the session is not active, all of its services are gone.
|
||||
DsfSession session = DsfSession.getSession(fSessionId);
|
||||
if (session == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
assert session.getExecutor().isInExecutorThread();
|
||||
|
||||
try {
|
||||
return fBundleContext.getServiceReferences(serviceClass, filter != null ? filter : fServiceFilter);
|
||||
} catch (InvalidSyntaxException e) {
|
||||
assert false : "Invalid session ID syntax"; //$NON-NLS-1$
|
||||
} catch (IllegalStateException e) {
|
||||
// Can occur when plugin is shutting down.
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to retrieve a service based on class name only.
|
||||
* @param serviceClass class of the desired service
|
||||
* @return instance of the desired service, null if not found
|
||||
*/
|
||||
|
@ -215,6 +249,16 @@ public class DsfServicesTracker {
|
|||
return getService(serviceClass, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to retrieve all services based on class name only.
|
||||
* @param serviceClass class of the desired service
|
||||
* @return List of instances of the desired service
|
||||
* @since 2.10
|
||||
*/
|
||||
public <V> Collection<V> getServices(Class<V> serviceClass) {
|
||||
return getServices(serviceClass, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the service given service class and optional filter.
|
||||
* Filter should be used if there are multiple instances of the desired service
|
||||
|
@ -231,6 +275,26 @@ public class DsfServicesTracker {
|
|||
return null;
|
||||
}
|
||||
|
||||
V service = getServiceHelper(serviceRef);
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all services for given optional filter.
|
||||
* Filter should be used if there are multiple instances of the desired service
|
||||
* running within the same session.
|
||||
* @param custom filter to use when searching for the service, this filter will
|
||||
* be used instead of the standard filter so it should also specify the desired
|
||||
* session-ID
|
||||
* @return List of instances of the desired services
|
||||
* @since 2.10
|
||||
*/
|
||||
public <V> Collection<V> getServices(Class<V> serviceClass, String filter) {
|
||||
return getServiceReferences(serviceClass, filter).stream().map(this::getServiceHelper)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private <V> V getServiceHelper(ServiceReference<V> serviceRef) {
|
||||
@SuppressWarnings("unchecked")
|
||||
V service = (V) fServices.get(serviceRef);
|
||||
if (service == null) {
|
||||
|
|
|
@ -715,7 +715,8 @@ public class GDBJtagDSFFinalLaunchSequence extends FinalLaunchSequence {
|
|||
fGdbJtagDevice.doContinue(commands);
|
||||
queueCommands(commands, rm);
|
||||
} else {
|
||||
rm.done();
|
||||
// Force UI to refresh collected data from target as it might have changed with complex GDB commands like 'load'.
|
||||
fCommandControl.flushAllCachesAndRefresh(rm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue