1
0
Fork 0
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:
Torbjörn Svensson 2020-11-20 07:40:33 +01:00 committed by Jonah Graham
parent 3ffe2156ff
commit 293998da18
9 changed files with 176 additions and 4 deletions

View file

@ -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,

View file

@ -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();
}
}

View file

@ -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$
}
}
}

View file

@ -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>

View file

@ -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,

View file

@ -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) {
}
}

View file

@ -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

View file

@ -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) {

View file

@ -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);
}
}