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

Bug 338319: Allow terminating individual processes

This commit is contained in:
Marc Khouzam 2011-03-02 11:06:15 +00:00
parent 4c700d7e5f
commit e03d0d8880
10 changed files with 283 additions and 257 deletions

View file

@ -30,9 +30,11 @@ import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContex
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.launching.GDBProcess;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
@ -45,6 +47,7 @@ import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager;
import org.eclipse.cdt.dsf.mi.service.MIProcesses;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess.State;
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
@ -53,6 +56,7 @@ import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
@ -74,6 +78,11 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
private IGDBBackend fBackend;
private CommandFactory fCommandFactory;
// Indicates if we are currently connected to an inferior
// We only need a boolean type since we only support single process debugging
// in this version of the service
private boolean fConnected;
// A map of pid to names. It is filled when we get all the
// processes that are running
private Map<Integer, String> fProcessNames = new HashMap<Integer, String>();
@ -114,10 +123,6 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
GDBProcesses.class.getName() },
new Hashtable<String, String>());
ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class);
IContainerDMContext containerDmc = createContainerContextFromGroupId(commandControl.getContext(), MIProcesses.UNIQUE_GROUP_ID);
fGdb.getInferiorProcess().setContainerContext(containerDmc);
getSession().addServiceEventListener(this, null);
requestMonitor.done();
@ -195,11 +200,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
@Override
public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
if (!fGdb.isConnected() &&
inferiorProcess != null &&
inferiorProcess.getState() != MIInferiorProcess.State.TERMINATED) {
if (fBackend.getIsAttachSession() && !fConnected) {
rm.setData(true);
} else {
rm.setData(false);
@ -213,7 +214,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
// For a local attach, GDB can figure out the binary automatically,
// so we don't specify it.
IMIContainerDMContext containerDmc = createContainerContext(procCtx, MIProcesses.UNIQUE_GROUP_ID);
final IMIContainerDMContext containerDmc = createContainerContext(procCtx, MIProcesses.UNIQUE_GROUP_ID);
DataRequestMonitor<MIInfo> attachRm = new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
@ -223,10 +224,9 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
new DataRequestMonitor<IDMContext>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
fGdb.setConnected(true);
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
if (inferiorProcess != null) {
inferiorProcess.setContainerContext(containerDmc);
inferiorProcess.setPid(((IMIProcessDMContext)procCtx).getProcId());
}
@ -258,7 +258,11 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
@Override
public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
rm.setData(false); // don't turn on yet, as we need to generate events to use this properly
if (fBackend.getIsAttachSession() && fConnected) {
rm.setData(true);
} else {
rm.setData(false);
}
rm.done();
}
@ -268,9 +272,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
dmc,
new RequestMonitor(getExecutor(), rm) {
@Override
protected void handleSuccess() {
fGdb.setConnected(false);
protected void handleSuccess() {
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
if (inferiorProcess != null) {
inferiorProcess.setPid(null);
@ -301,7 +303,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
@Override
public void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm) {
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
if (fGdb.isConnected() &&
if (fConnected &&
inferiorProcess != null &&
inferiorProcess.getState() != MIInferiorProcess.State.TERMINATED) {
@ -353,9 +355,37 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
}
@Override
public void terminate(IThreadDMContext thread, RequestMonitor rm) {
public void terminate(IThreadDMContext thread, final RequestMonitor rm) {
if (thread instanceof IMIProcessDMContext) {
fGdb.terminate(rm);
getDebuggingContext(
thread,
new DataRequestMonitor<IDMContext>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
if (getData() instanceof IMIContainerDMContext) {
if (fGdb.getInferiorProcess().getState() == State.RUNNING) {
fBackend.interrupt();
}
final IMIContainerDMContext container = (IMIContainerDMContext)getData();
fGdb.queueCommand(
fCommandFactory.createMIInterpreterExecConsoleKill(container),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
// Before GDB 7.0, we must send a container exited event ourselves
getSession().dispatchEvent(
new ContainerExitedDMEvent(container), getProperties());
rm.done();
}
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
}
}
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
@ -405,12 +435,13 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
/**
* @since 4.0
*/
protected void createConsole(final boolean restart, final RequestMonitor rm) {
protected void createConsole(final IContainerDMContext containerDmc, final boolean restart, final RequestMonitor rm) {
fGdb.initInferiorInputOutput(new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
fGdb.createInferiorProcess();
final Process inferior = fGdb.getInferiorProcess();
fGdb.createInferiorProcess();
final MIInferiorProcess inferior = fGdb.getInferiorProcess();
inferior.setContainerContext(containerDmc);
final String label = fBackend.getProgramPath().lastSegment();
final ILaunch launch = (ILaunch)getSession().getModelAdapter(ILaunch.class);
@ -459,55 +490,55 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
return;
}
createConsole(restart, new RequestMonitor(ImmediateExecutor.getInstance(), requestMonitor) {
createConsole(containerDmc, restart, new RequestMonitor(ImmediateExecutor.getInstance(), requestMonitor) {
@Override
protected void handleSuccess() {
final DataRequestMonitor<MIInfo> execMonitor = new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor) {
@Override
protected void handleSuccess() {
if (fBackend.getSessionType() != SessionType.REMOTE) {
// Don't send the ContainerStarted event for a remote session because
// it has already been done by MIRunControlEventProcessor when receiving
// the ^connect
getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc), getProperties());
}
requestMonitor.setData(containerDmc);
requestMonitor.done();
}
};
final ICommand<MIInfo> execCommand;
if (useContinueCommand()) {
execCommand = fCommandFactory.createMIExecContinue(containerDmc);
} else {
execCommand = fCommandFactory.createMIExecRun(containerDmc);
}
boolean stopInMain = CDebugUtils.getAttribute(attributes,
ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN,
false);
if (!stopInMain) {
// Just start the program.
fGdb.queueCommand(execCommand, execMonitor);
} else {
String stopSymbol = CDebugUtils.getAttribute(attributes,
ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL,
ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT);
// Insert a breakpoint at the requested stop symbol.
IBreakpointsTargetDMContext bpTarget = DMContexts.getAncestorOfType(containerDmc, IBreakpointsTargetDMContext.class);
fGdb.queueCommand(
fCommandFactory.createMIBreakInsert(bpTarget, true, false, null, 0, stopSymbol, 0),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), requestMonitor) {
@Override
protected void handleSuccess() {
// After the break-insert is done, execute the -exec-run or -exec-continue command.
fGdb.queueCommand(execCommand, execMonitor);
final DataRequestMonitor<MIInfo> execMonitor = new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor) {
@Override
protected void handleSuccess() {
if (fBackend.getSessionType() != SessionType.REMOTE) {
// Don't send the ContainerStarted event for a remote session because
// it has already been done by MIRunControlEventProcessor when receiving
// the ^connect
getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc), getProperties());
}
});
}
requestMonitor.setData(containerDmc);
requestMonitor.done();
}
};
final ICommand<MIInfo> execCommand;
if (useContinueCommand()) {
execCommand = fCommandFactory.createMIExecContinue(containerDmc);
} else {
execCommand = fCommandFactory.createMIExecRun(containerDmc);
}
boolean stopInMain = CDebugUtils.getAttribute(attributes,
ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN,
false);
if (!stopInMain) {
// Just start the program.
fGdb.queueCommand(execCommand, execMonitor);
} else {
String stopSymbol = CDebugUtils.getAttribute(attributes,
ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL,
ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT);
// Insert a breakpoint at the requested stop symbol.
IBreakpointsTargetDMContext bpTarget = DMContexts.getAncestorOfType(containerDmc, IBreakpointsTargetDMContext.class);
fGdb.queueCommand(
fCommandFactory.createMIBreakInsert(bpTarget, true, false, null, 0, stopSymbol, 0),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), requestMonitor) {
@Override
protected void handleSuccess() {
// After the break-insert is done, execute the -exec-run or -exec-continue command.
fGdb.queueCommand(execCommand, execMonitor);
}
});
}
}
});
}
@ -524,6 +555,31 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
return fBackend.getSessionType() == SessionType.REMOTE;
}
@Override
@DsfServiceEventHandler
public void eventDispatched(IStartedDMEvent e) {
if (e.getDMContext() instanceof IContainerDMContext) {
fConnected = true;
}
super.eventDispatched(e);
}
@Override
@DsfServiceEventHandler
public void eventDispatched(IExitedDMEvent e) {
if (e.getDMContext() instanceof IContainerDMContext) {
fConnected = false;
if (Platform.getPreferencesService().getBoolean("org.eclipse.cdt.dsf.gdb.ui", //$NON-NLS-1$
IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB,
true, null)) {
// If the inferior finishes, let's terminate GDB
fGdb.terminate(new RequestMonitor(ImmediateExecutor.getInstance(), null));
}
}
super.eventDispatched(e);
}
/**
* @since 3.0
*/

View file

@ -50,6 +50,7 @@ import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
@ -60,6 +61,8 @@ import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager;
import org.eclipse.cdt.dsf.mi.service.MIProcesses;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess.State;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadGroupCreatedEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadGroupExitedEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIConst;
@ -79,6 +82,7 @@ import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
import org.osgi.framework.BundleContext;
@ -436,6 +440,11 @@ public class GDBProcesses_7_0 extends AbstractDsfService
private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$
/**
* Keeps track of how many processes we are currently connected to
*/
private int fNumConnected;
/**
* Keeps track if we are dealing with the very first process of GDB.
*/
@ -725,7 +734,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
/** @since 4.0 */
protected boolean doIsDebuggerAttachSupported() {
return fBackend.getIsAttachSession() && !fCommandControl.isConnected();
return fBackend.getIsAttachSession() && fNumConnected == 0;
}
public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
@ -790,7 +799,14 @@ public class GDBProcesses_7_0 extends AbstractDsfService
public void execute(RequestMonitor rm) {
// By now, GDB has reported the groupId that was created for this process
fContainerDmc = createContainerContext(procCtx, getGroupFromPid(((IMIProcessDMContext)procCtx).getProcId()));
// Store the fully formed container context so it can be returned to the caller.
MIInferiorProcess inferior = fCommandControl.getInferiorProcess();
if (inferior != null) {
inferior.setContainerContext(fContainerDmc);
inferior.setPid(((IMIProcessDMContext)procCtx).getProcId());
}
// Store the fully formed container context so it can be returned to the caller.
dataRm.setData(fContainerDmc);
// Start tracking breakpoints.
@ -835,7 +851,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
/** @since 4.0 */
protected boolean doCanDetachDebuggerFromProcess() {
return fBackend.getIsAttachSession() && fCommandControl.isConnected();
return fBackend.getIsAttachSession() && fNumConnected > 0;
}
public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
@ -857,7 +873,13 @@ public class GDBProcesses_7_0 extends AbstractDsfService
fCommandControl.queueCommand(
fCommandFactory.createMITargetDetach(controlDmc, procDmc.getProcId()),
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
fCommandControl.getInferiorProcess().setPid(null);
rm.done();
}
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$
rm.done();
@ -1096,9 +1118,27 @@ public class GDBProcesses_7_0 extends AbstractDsfService
rm.done();
}
public void terminate(IThreadDMContext thread, RequestMonitor rm) {
public void terminate(IThreadDMContext thread, final RequestMonitor rm) {
if (thread instanceof IMIProcessDMContext) {
fCommandControl.terminate(rm);
getDebuggingContext(
thread,
new DataRequestMonitor<IDMContext>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
if (getData() instanceof IMIContainerDMContext) {
if (fCommandControl.getInferiorProcess().getState() == State.RUNNING) {
fBackend.interrupt();
}
fCommandControl.queueCommand(
fCommandFactory.createMIInterpreterExecConsoleKill((IMIContainerDMContext)getData()),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
}
}
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
@ -1214,6 +1254,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
public void eventDispatched(IStartedDMEvent e) {
if (e instanceof ContainerStartedDMEvent) {
fContainerCommandCache.reset();
fNumConnected++;
} else {
fThreadCommandCache.reset();
}
@ -1224,6 +1265,22 @@ public class GDBProcesses_7_0 extends AbstractDsfService
public void eventDispatched(IExitedDMEvent e) {
if (e instanceof ContainerExitedDMEvent) {
fContainerCommandCache.reset();
assert fNumConnected > 0;
fNumConnected--;
if (Platform.getPreferencesService().getBoolean("org.eclipse.cdt.dsf.gdb.ui", //$NON-NLS-1$
IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB,
true, null)) {
if (fNumConnected == 0 &&
!(fBackend.getIsAttachSession() &&
fBackend.getSessionType() == SessionType.REMOTE)) {
// If the last process we are debugging finishes, let's terminate GDB
// but not for a remote attach session, since we could request to attach
// to another process
fCommandControl.terminate(new RequestMonitor(ImmediateExecutor.getInstance(), null));
}
}
} else {
fThreadCommandCache.reset();
}

View file

@ -30,6 +30,7 @@ import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint;
@ -333,6 +334,11 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
if (fContainerDmc instanceof IMIContainerDMContext) {
fContainerDmc = fProcService.createContainerContextFromGroupId(fCommandControl.getContext(), ((IMIContainerDMContext)fContainerDmc).getGroupId());
fCommandControl.getInferiorProcess().setContainerContext(fContainerDmc);
IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(fContainerDmc, IMIProcessDMContext.class);
fCommandControl.getInferiorProcess().setPid(procDmc.getProcId());
// This is the container context that this sequence is supposed to return: set the dataRm
fDataRequestMonitor.setData(fContainerDmc);
} else {

View file

@ -28,20 +28,17 @@ 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.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Sequence;
import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.gdb.service.SessionType;
import org.eclipse.cdt.dsf.mi.service.IMIBackend;
import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerExitedDMEvent;
import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess;
import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl;
import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor;
@ -55,7 +52,6 @@ import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.osgi.framework.BundleContext;
@ -94,9 +90,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
private GDBControlDMContext fControlDmc;
private IGDBBackend fMIBackend;
private boolean fConnected;
private MIRunControlEventProcessor fMIEventProcessor;
private CLIEventProcessor fCLICommandProcessor;
private AbstractCLIProcess fCLIProcess;
@ -264,9 +258,9 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
*/
public void createInferiorProcess() {
if (fPty == null) {
fInferiorProcess = new GDBInferiorProcess(GDBControl.this, fMIBackend, fMIBackend.getMIOutputStream());
fInferiorProcess = new MIInferiorProcess(GDBControl.this, fMIBackend.getMIOutputStream());
} else {
fInferiorProcess = new GDBInferiorProcess(GDBControl.this, fMIBackend, fPty);
fInferiorProcess = new MIInferiorProcess(GDBControl.this, fPty);
}
// Create the CLI event processor each time this method is called
@ -277,16 +271,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
}
fCLICommandProcessor = new CLIEventProcessor(GDBControl.this, fControlDmc);
}
public boolean isConnected() {
return fInferiorProcess.getState() != MIInferiorProcess.State.TERMINATED &&
(!fMIBackend.getIsAttachSession() || fConnected);
}
public void setConnected(boolean connected) {
fConnected = connected;
}
public AbstractCLIProcess getCLIProcess() {
return fCLIProcess;
}
@ -341,17 +326,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
}
}
/** @since 2.0 */
@DsfServiceEventHandler
public void eventDispatched(ContainerExitedDMEvent e) {
if (Platform.getPreferencesService().getBoolean("org.eclipse.cdt.dsf.gdb.ui", //$NON-NLS-1$
IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB,
true, null)) {
// If the inferior finishes, let's terminate GDB
terminate(new RequestMonitor(ImmediateExecutor.getInstance(), null));
}
}
public static class InitializationShutdownStep extends Sequence.Step {
public enum Direction { INITIALIZING, SHUTTING_DOWN }

View file

@ -28,16 +28,12 @@ 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.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Sequence;
import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.GDBProcesses_7_0.ContainerExitedDMEvent;
import org.eclipse.cdt.dsf.gdb.service.GDBProcesses_7_0.ContainerStartedDMEvent;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent;
import org.eclipse.cdt.dsf.gdb.service.SessionType;
@ -58,7 +54,6 @@ import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.osgi.framework.BundleContext;
@ -97,8 +92,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
private GDBControlDMContext fControlDmc;
private IGDBBackend fMIBackend;
private int fConnected = 0;
private MIRunControlEventProcessor_7_0 fMIEventProcessor;
private CLIEventProcessor_7_0 fCLICommandProcessor;
@ -281,25 +274,12 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
*/
public void createInferiorProcess() {
if (fPty == null) {
fInferiorProcess = new GDBInferiorProcess(GDBControl_7_0.this, fMIBackend, fMIBackend.getMIOutputStream());
fInferiorProcess = new MIInferiorProcess(GDBControl_7_0.this, fMIBackend.getMIOutputStream());
} else {
fInferiorProcess = new GDBInferiorProcess(GDBControl_7_0.this, fMIBackend, fPty);
fInferiorProcess = new MIInferiorProcess(GDBControl_7_0.this, fPty);
}
}
public boolean isConnected() {
return fInferiorProcess.getState() != MIInferiorProcess.State.TERMINATED &&
(!fMIBackend.getIsAttachSession() || fConnected > 0);
}
public void setConnected(boolean connected) {
if (connected) {
fConnected++;
} else {
if (fConnected > 0) fConnected--;
}
}
public AbstractCLIProcess getCLIProcess() {
return fCLIProcess;
}
@ -358,31 +338,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
getSession().dispatchEvent(new GDBControlShutdownDMEvent(fControlDmc), getProperties());
}
}
/** @since 2.0 */
@DsfServiceEventHandler
public void eventDispatched(ContainerStartedDMEvent e) {
setConnected(true);
}
/** @since 2.0 */
@DsfServiceEventHandler
public void eventDispatched(ContainerExitedDMEvent e) {
setConnected(false);
if (Platform.getPreferencesService().getBoolean("org.eclipse.cdt.dsf.gdb.ui", //$NON-NLS-1$
IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB,
true, null)) {
if (!isConnected() &&
!(fMIBackend.getIsAttachSession() &&
fMIBackend.getSessionType() == SessionType.REMOTE)) {
// If the last process we are debugging finishes, let's terminate GDB
// but not for a remote attach session, since we could request to attach
// to another process
terminate(new RequestMonitor(ImmediateExecutor.getInstance(), null));
}
}
}
/** @since 3.0 */
@DsfServiceEventHandler

View file

@ -1,72 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007, 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.gdb.service.command;
import java.io.OutputStream;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
import org.eclipse.cdt.utils.pty.PTY;
/**
*
*/
class GDBInferiorProcess extends MIInferiorProcess {
private IGDBBackend fBackend;
public GDBInferiorProcess(ICommandControlService commandControl, IGDBBackend backend, PTY p) {
super(commandControl, p);
fBackend = backend;
}
public GDBInferiorProcess(ICommandControlService commandControl, IGDBBackend backend, OutputStream gdbOutputStream) {
super(commandControl, gdbOutputStream);
fBackend = backend;
}
@Override
@ThreadSafeAndProhibitedFromDsfExecutor("getSession#getExecutor")
public void destroy() {
try {
getSession().getExecutor().submit(new DsfRunnable() {
public void run() {
if (isDisposed() || !getSession().isActive()) return;
// An inferior will be destroy():interrupt and kill if
// - For attach session:
// never (we don't kill an independent process.)
// - For Program session:
// if the inferior is still running.
// - For PostMortem(Core):
// no need to do anything since the inferior
// is not running
if (fBackend.getIsAttachSession() == false) {
// Try to interrupt the inferior, first.
if (getState() == State.RUNNING) {
fBackend.interrupt();
}
}
}
}).get();
} catch (RejectedExecutionException e) {
} catch (InterruptedException e) {
} catch (ExecutionException e) {
} finally {
super.destroy();
}
}
}

View file

@ -28,10 +28,6 @@ public interface IGDBControl extends IMICommandControl {
void createInferiorProcess();
boolean isConnected();
void setConnected(boolean connected);
AbstractCLIProcess getCLIProcess();
MIInferiorProcess getInferiorProcess();

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2010 QNX Software Systems and others.
* Copyright (c) 2000, 2011 QNX Software 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
@ -68,6 +68,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataWriteMemory;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIEnablePrettyPrinting;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIEnvironmentCD;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIEnvironmentDirectory;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecArguments;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecFinish;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecInterrupt;
@ -103,6 +104,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBShowExitCode;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIInferiorTTYSet;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIInterpreterExec;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIInterpreterExecConsole;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIInterpreterExecConsoleKill;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIListFeatures;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIListThreadGroups;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIRemoveInferior;
@ -143,7 +145,6 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarSetUpdateRange;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowAttributes;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowFormat;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarUpdate;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecArguments;
import org.eclipse.cdt.dsf.mi.service.command.output.CLICatchInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoProgramInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoSharedLibraryInfo;
@ -632,6 +633,11 @@ public class CommandFactory {
return new MIInterpreterExecConsole<MIInfo>(ctx, cmd);
}
/** @since 4.0 */
public ICommand<MIInfo> createMIInterpreterExecConsoleKill(IMIContainerDMContext ctx) {
return new MIInterpreterExecConsoleKill(ctx);
}
/** @since 4.0 */
public ICommand<MIListFeaturesInfo> createMIListFeatures(ICommandControlDMContext ctx) {
return new MIListFeatures(ctx);

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2009, 2010 QNX Software Systems and others.
* Copyright (c) 2009, 2011 QNX Software 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
@ -28,11 +28,15 @@ 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.concurrent.Query;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IProcesses;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
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.command.ICommand;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.debug.service.command.ICommandListener;
import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
@ -52,6 +56,8 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResultRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MITargetStreamOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.core.runtime.CoreException;
@ -124,8 +130,6 @@ public class MIInferiorProcess extends Process
* to write the user standard input into.
*
* @param commandControl Command control that this inferior process belongs to.
* @param inferiorExecCtx The execution context controlling the execution
* state of the inferior process.
* @param gdbOutputStream The output stream to use to write user IO into.
* @since 1.1
*/
@ -139,8 +143,6 @@ public class MIInferiorProcess extends Process
* to write the user standard input into.
*
* @param commandControl Command control that this inferior process belongs to.
* @param inferiorExecCtx The execution context controlling the execution
* state of the inferior process.
* @param p The terminal to use to write user IO into.
* @since 1.1
*/
@ -153,7 +155,8 @@ public class MIInferiorProcess extends Process
private MIInferiorProcess(ICommandControlService commandControl, final OutputStream gdbOutputStream, PTY p) {
fCommandControl = commandControl;
fSession = commandControl.getSession();
fSession.addServiceEventListener(this, null);
if (fCommandControl instanceof IMICommandControl) {
fCommandFactory = ((IMICommandControl)fCommandControl).getCommandFactory();
} else {
@ -173,7 +176,6 @@ public class MIInferiorProcess extends Process
fOutputStream = new OutputStream() {
@Override
public void write(int b) throws IOException {
// Have to re-dispatch to dispatch thread to check state
if (getState() != State.RUNNING) {
throw new IOException("Target is not running"); //$NON-NLS-1$
}
@ -206,6 +208,8 @@ public class MIInferiorProcess extends Process
@ConfinedToDsfExecutor("fSession#getExecutor")
public void dispose() {
fSession.removeServiceEventListener(this);
fCommandControl.removeEventListener(this);
fCommandControl.removeCommandListener(this);
@ -369,18 +373,15 @@ public class MIInferiorProcess extends Process
private void doDestroy() {
if (isDisposed() || !fSession.isActive() || getState() == State.TERMINATED) return;
// To avoid a RejectedExecutionException, use an executor that
// immediately executes in the same dispatch cycle.
ICommand<MIInfo> cmd = fCommandFactory.createCLIExecAbort(getCommandControlService().getContext());
getCommandControlService().queueCommand(
cmd,
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), null) {
@Override
protected void handleCompleted() {
setState(MIInferiorProcess.State.TERMINATED);
}
}
);
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSession.getId());
IProcesses procService = tracker.getService(IProcesses.class);
tracker.dispose();
if (procService != null) {
IProcessDMContext procDmc = DMContexts.getAncestorOfType(fContainerDMContext, IProcessDMContext.class);
procService.terminate(procDmc, new RequestMonitor(ImmediateExecutor.getInstance(), null));
} else {
setState(State.TERMINATED);
}
}
@ThreadSafe
@ -406,12 +407,6 @@ public class MIInferiorProcess extends Process
if (fState == State.TERMINATED) return;
fState = state;
if (fState == State.TERMINATED) {
if (fContainerDMContext != null) {
// This may not be necessary in 7.0 because of the =thread-group-exited event
getSession().dispatchEvent(
new ContainerExitedDMEvent(fContainerDMContext),
getCommandControlService().getProperties());
}
closeIO();
}
notifyAll();
@ -466,7 +461,14 @@ public class MIInferiorProcess extends Process
if (value instanceof MIConst) {
String reason = ((MIConst) value).getString();
if ("exited-signalled".equals(reason) || "exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
setState(State.TERMINATED);
if (fContainerDMContext != null) {
// This may not be necessary in 7.0 because of the =thread-group-exited event
getSession().dispatchEvent(
new ContainerExitedDMEvent(fContainerDMContext),
getCommandControlService().getProperties());
} else {
setState(State.TERMINATED);
}
} else {
setState(State.STOPPED);
}
@ -520,10 +522,29 @@ public class MIInferiorProcess extends Process
String state = rr.getResultClass();
if ("running".equals(state)) { setState(State.RUNNING); }//$NON-NLS-1$
else if ("exit".equals(state)) { setState(State.TERMINATED); }//$NON-NLS-1$
else if ("exit".equals(state)) { //$NON-NLS-1$
if (fContainerDMContext != null) {
// This may not be necessary in 7.0 because of the =thread-group-exited event
getSession().dispatchEvent(
new ContainerExitedDMEvent(fContainerDMContext),
getCommandControlService().getProperties());
} else {
setState(State.TERMINATED);
}
}
else if ("error".equals(state)) { setState(State.STOPPED); }//$NON-NLS-1$
}
/**
* @since 4.0
*/
@DsfServiceEventHandler
public void eventDispatched(IExitedDMEvent e) {
if (e.getDMContext() instanceof IContainerDMContext) {
setState(State.TERMINATED);
}
}
//
// Post-poned because 'info program' yields different result on different platforms.
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=305385#c20

View file

@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright (c) 2011 Ericsson 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:
* Ericsson - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
/**
* MIInterpreterExecConsoleKill
* Send the CLI Kill command for a specific process.
* @since 4.0
*/
public class MIInterpreterExecConsoleKill extends MIInterpreterExecConsole<MIInfo> {
public MIInterpreterExecConsoleKill(IMIContainerDMContext ctx) {
super(ctx, "kill"); //$NON-NLS-1$
}
}