1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

[280461] Introduce a way to add extra executor depths to preserve the order of MI events and MI command results

This commit is contained in:
Marc Khouzam 2009-11-03 15:58:38 +00:00
parent 29e5a63132
commit 75e6f8510f
8 changed files with 266 additions and 22 deletions

View file

@ -36,6 +36,7 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
@ -428,12 +429,23 @@ public class GDBProcesses_7_0 extends AbstractDsfService
fCommandControl = getServicesTracker().getService(IGDBControl.class);
fBackend = getServicesTracker().getService(IGDBBackend.class);
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(fCommandControl, getExecutor(), 2);
fContainerCommandCache = new CommandCache(getSession(), fCommandControl);
// These caches store the result of a command when received; also, these caches
// are manipulated when receiving events. Currently, events are received after
// three scheduling of the executor, while command results after only one. This
// can cause problems because command results might be processed before an event
// that actually arrived before the command result.
// To solve this, we use a bufferedCommandControl that will delay the command
// result by two scheduling of the executor.
// See bug 280461
fContainerCommandCache = new CommandCache(getSession(), bufferedCommandControl);
fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true);
fThreadCommandCache = new CommandCache(getSession(), fCommandControl);
fThreadCommandCache = new CommandCache(getSession(), bufferedCommandControl);
fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true);
// No need to use the bufferedCommandControl for the listThreadGroups cache
// because it is not being affected by events.
fListThreadGroupsAvailableCache = new CommandCache(getSession(), fCommandControl);
fListThreadGroupsAvailableCache.setContextAvailable(fCommandControl.getContext(), true);
@ -757,7 +769,6 @@ public class GDBProcesses_7_0 extends AbstractDsfService
final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
if (controlDmc != null) {
// Don't cache this command since the list can change at any time.
fListThreadGroupsAvailableCache.execute(
new MIListThreadGroups(controlDmc, true),
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {

View file

@ -37,6 +37,7 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
@ -127,7 +128,17 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
private void doInitialize(final RequestMonitor requestMonitor) {
// Create the command cache
ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class);
fCommandCache = new CommandCache(getSession(), commandControl);
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(commandControl, getExecutor(), 2);
// This cache stores the result of a command when received; also, this cache
// is manipulated when receiving events. Currently, events are received after
// three scheduling of the executor, while command results after only one. This
// can cause problems because command results might be processed before an event
// that actually arrived before the command result.
// To solve this, we use a bufferedCommandControl that will delay the command
// result by two scheduling of the executor.
// See bug 280461
fCommandCache = new CommandCache(getSession(), bufferedCommandControl);
fCommandCache.setContextAvailable(commandControl.getContext(), true);
// Register this service

View file

@ -28,6 +28,7 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
@ -347,7 +348,17 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses, ICa
// new Hashtable<String, String>());
fCommandControl = getServicesTracker().getService(ICommandControlService.class);
fContainerCommandCache = new CommandCache(getSession(), fCommandControl);
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(fCommandControl, getExecutor(), 2);
// This cache stores the result of a command when received; also, this cache
// is manipulated when receiving events. Currently, events are received after
// three scheduling of the executor, while command results after only one. This
// can cause problems because command results might be processed before an event
// that actually arrived before the command result.
// To solve this, we use a bufferedCommandControl that will delay the command
// result by two scheduling of the executor.
// See bug 280461
fContainerCommandCache = new CommandCache(getSession(), bufferedCommandControl);
fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true);
getSession().addServiceEventListener(this, null);

View file

@ -25,6 +25,7 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
@ -172,8 +173,20 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach
* Create the lower level register cache.
*/
ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class);
fRegisterValueCache = new CommandCache(getSession(), commandControl);
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(commandControl, getExecutor(), 2);
// This cache stores the result of a command when received; also, this cache
// is manipulated when receiving events. Currently, events are received after
// three scheduling of the executor, while command results after only one. This
// can cause problems because command results might be processed before an event
// that actually arrived before the command result.
// To solve this, we use a bufferedCommandControl that will delay the command
// result by two scheduling of the executor.
// See bug 280461
fRegisterValueCache = new CommandCache(getSession(), bufferedCommandControl);
fRegisterValueCache.setContextAvailable(commandControl.getContext(), true);
// This cache is not affected by events so does not need the bufferedCommandControl
fRegisterNameCache = new CommandCache(getSession(), commandControl);
fRegisterNameCache.setContextAvailable(commandControl.getContext(), true);

View file

@ -21,6 +21,7 @@ import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
@ -288,7 +289,17 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
private void doInitialize(final RequestMonitor rm) {
fConnection = getServicesTracker().getService(ICommandControlService.class);
fMICommandCache = new CommandCache(getSession(), fConnection);
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(fConnection, getExecutor(), 2);
// This cache stores the result of a command when received; also, this cache
// is manipulated when receiving events. Currently, events are received after
// three scheduling of the executor, while command results after only one. This
// can cause problems because command results might be processed before an event
// that actually arrived before the command result.
// To solve this, we use a bufferedCommandControl that will delay the command
// result by two scheduling of the executor.
// See bug 280461
fMICommandCache = new CommandCache(getSession(), bufferedCommandControl);
fMICommandCache.setContextAvailable(fConnection.getContext(), true);
getSession().addServiceEventListener(this, null);
rm.done();

View file

@ -31,6 +31,7 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
@ -190,7 +191,17 @@ public class MIStack extends AbstractDsfService
private void doInitialize(RequestMonitor rm) {
ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class);
fMICommandCache = new CommandCache(getSession(), commandControl);
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(commandControl, getExecutor(), 2);
// This cache stores the result of a command when received; also, this cache
// is manipulated when receiving events. Currently, events are received after
// three scheduling of the executor, while command results after only one. This
// can cause problems because command results might be processed before an event
// that actually arrived before the command result.
// To solve this, we use a bufferedCommandControl that will delay the command
// result by two scheduling of the executor.
// See bug 280461
fMICommandCache = new CommandCache(getSession(), bufferedCommandControl);
fMICommandCache.setContextAvailable(commandControl.getContext(), true);
fRunControl = getServicesTracker().getService(IRunControl.class);

View file

@ -0,0 +1,149 @@
/*******************************************************************************
* Copyright (c) 2009 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
*******************************************************************************/
package org.eclipse.cdt.dsf.debug.service.command;
import java.util.ArrayList;
import java.util.List;
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.ImmediateExecutor;
/**
* A command control which delays the <strong>results</strong> of commands
* sent to a command control, as well as events from the command control.
* The delay is specified in the constructor using a number of executor
* dispatch cycles.
*
* @since 2.1
*/
public class BufferedCommandControl implements ICommandControl {
private DsfExecutor fExecutor;
private ICommandControl fControlDelegate;
private int fDepth;
private ICommandListener fCommandListener = new ICommandListener() {
public void commandQueued(ICommandToken token) {
for (ICommandListener processor : fCommandProcessors) {
processor.commandQueued(token);
}
};
public void commandRemoved(ICommandToken token) {
for (ICommandListener processor : fCommandProcessors) {
processor.commandRemoved(token);
}
};
public void commandSent(final ICommandToken token) {
for (ICommandListener processor : fCommandProcessors) {
processor.commandSent(token);
}
};
public void commandDone(final ICommandToken token, final ICommandResult result) {
buffer(fDepth, new DsfRunnable() {
public void run() {
for (ICommandListener processor : fCommandProcessors) {
processor.commandDone(token, result);
}
};
});
};
};
private IEventListener fEventListener = new IEventListener() {
public void eventReceived(final Object output) {
buffer(fDepth, new DsfRunnable() {
public void run() {
for (IEventListener processor : fEventProcessors) {
processor.eventReceived(output);
}
};
});
}
};
private final List<ICommandListener> fCommandProcessors = new ArrayList<ICommandListener>();
private final List<IEventListener> fEventProcessors = new ArrayList<IEventListener>();
public BufferedCommandControl(ICommandControl controlDelegate, DsfExecutor executor, int depth) {
fControlDelegate = controlDelegate;
fExecutor = executor;
fDepth = depth;
assert fDepth > 0;
}
public void addCommandListener(ICommandListener listener) {
if (fCommandProcessors.isEmpty()) {
fControlDelegate.addCommandListener(fCommandListener);
}
fCommandProcessors.add(listener);
}
public void removeCommandListener(ICommandListener listener) {
fCommandProcessors.remove(listener);
if (fCommandProcessors.isEmpty()) {
fControlDelegate.removeCommandListener(fCommandListener);
}
}
public void addEventListener(IEventListener listener) {
if (fEventProcessors.isEmpty()) {
fControlDelegate.addEventListener(fEventListener);
}
fEventProcessors.add(listener);
}
public void removeEventListener(IEventListener listener) {
fEventProcessors.remove(listener);
if (fEventProcessors.isEmpty()) {
fControlDelegate.removeEventListener(fEventListener);
}
}
public <V extends ICommandResult> ICommandToken queueCommand(final ICommand<V> command, final DataRequestMonitor<V> rm) {
return fControlDelegate.queueCommand(
command,
new DataRequestMonitor<V>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleCompleted() {
buffer(fDepth, new DsfRunnable() {
public void run() {
rm.setData(getData());
rm.setStatus(getStatus());
rm.done();
}
});
}
});
}
public void removeCommand(ICommandToken token) {
fControlDelegate.removeCommand(token);
}
private void buffer(final int depth, final DsfRunnable runnable) {
if (depth == 0) {
runnable.run();
} else {
fExecutor.execute(new DsfRunnable() {
public void run() {
buffer(depth - 1, runnable);
}
});
}
}
}

View file

@ -22,7 +22,9 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.internal.DsfPlugin;
@ -118,6 +120,13 @@ public class CommandCache implements ICommandListener
private DsfSession fSession;
/**
* The command control to be used to send commands to the backend.
* In certain cases, a {@link BufferedCommandControl} should be used
* to artificially delay the processing of command results; these
* artificial delays are important to keep events and command results
* ordered as received by the backend.
*/
private ICommandControl fCommandControl;
/*
@ -384,7 +393,24 @@ public class CommandCache implements ICommandListener
finalCachedCmd.fToken = fCommandControl.queueCommand(
finalCachedCmd.getCommand(),
new DataRequestMonitor<ICommandResult>(fSession.getExecutor(), null) {
new DataRequestMonitor<ICommandResult>(ImmediateExecutor.getInstance(), null) {
@Override
public synchronized void done() {
// protect against the cache being called in non-session thread, but at
// the same time avoid adding extra dispatch cycles to command processing.
if (fSession.getExecutor().isInExecutorThread()) {;
super.done();
} else {
fSession.getExecutor().execute(new DsfRunnable() {
public void run() {
superDone();
}
});
}
}
private void superDone() {
super.done();
}
@Override
public void handleCompleted() {
@ -462,20 +488,21 @@ public class CommandCache implements ICommandListener
}
}
} else {
/*
* This is an original request which completed. Indicate success or
* failure to the original requesters.
*/
CommandResultInfo resultInfo = new CommandResultInfo(result, status);
// Save the command result in cache, but only if the command's context
// is still available. Otherwise an error may get cached incorrectly.
if (isTargetAvailable(context)) {
CommandResultInfo resultInfo = new CommandResultInfo(result, status);
if (fCachedContexts.get(context) != null){
fCachedContexts.get(context).put(finalCachedCmd, resultInfo);
} else {
HashMap<CommandInfo, CommandResultInfo> map = new HashMap<CommandInfo, CommandResultInfo>();
map.put(finalCachedCmd, resultInfo);
fCachedContexts.put(context, map);
}
if (fCachedContexts.get(context) != null){
fCachedContexts.get(context).put(finalCachedCmd, resultInfo);
} else {
HashMap<CommandInfo, CommandResultInfo> map = new HashMap<CommandInfo, CommandResultInfo>();
map.put(finalCachedCmd, resultInfo);
fCachedContexts.put(context, map);
}
}
// This is an original request which completed. Indicate success or
// failure to the original requesters.
if (!isSuccess()) {
/*
* We had some form of error with the original command. So notify the