1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Bug 237308: Support for multiple inferior processes

This commit is contained in:
Marc Khouzam 2011-02-25 20:08:11 +00:00
parent f561817d6e
commit f37667bcd3
8 changed files with 161 additions and 185 deletions

View file

@ -16,26 +16,19 @@ import java.util.Map;
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.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.ui.actions.DsfCommandRunnable;
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
import org.eclipse.cdt.dsf.gdb.launching.GDBProcess;
import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.commands.IDebugCommandRequest;
import org.eclipse.debug.core.commands.IEnabledStateRequest;
import org.eclipse.debug.core.commands.IRestartHandler;
import org.eclipse.debug.core.model.IProcess;
public class GdbRestartCommand implements IRestartHandler {
private final DsfExecutor fExecutor;
@ -82,107 +75,42 @@ public class GdbRestartCommand implements IRestartHandler {
});
}
private class UpdateLaunchJob extends Job {
IDebugCommandRequest fRequest;
UpdateLaunchJob(IDebugCommandRequest request) {
super(""); //$NON-NLS-1$
setSystem(true);
fRequest = request;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
// Before restarting the inferior, we must add it to our launch
// we must do this here because we cannot do it in the executor, or else
// it deadlocks
// We must first remove the old inferior from our launch so that we
// can re-use its name
// Remove
String inferiorLabel = null;
IProcess[] launchProcesses = fLaunch.getProcesses();
for (IProcess p : launchProcesses) {
if ((p instanceof GDBProcess) == false) {
// We have to processes in our launches, GDB and the inferior
// We can tell this is the inferior because it is not GDB.
// If we don't have an inferior at all, we just won't find it.
inferiorLabel = p.getLabel();
fLaunch.removeProcess(p);
break;
}
}
// Add
if (inferiorLabel != null) {
try {
fLaunch.addInferiorProcess(inferiorLabel);
} catch (CoreException e) {
}
}
// Now that we have added the new inferior to the launch,
// which creates its console, we can perform the restart safely.
fExecutor.submit(new DsfCommandRunnable(fTracker, fRequest.getElements()[0], fRequest) {
@SuppressWarnings("unchecked")
@Override public void doExecute() {
IContainerDMContext containerDmc = DMContexts.getAncestorOfType(getContext(), IContainerDMContext.class);
IGDBProcesses procService = fTracker.getService(IGDBProcesses.class);
if (procService != null) {
Map<String, Object> attributes = null;
try {
attributes = fLaunch.getLaunchConfiguration().getAttributes();
} catch (CoreException e) {}
procService.restart(containerDmc, attributes,
new DataRequestMonitor<IContainerDMContext>(fExecutor, null) {
@Override
protected void handleCompleted() {
fRequest.done();
};
});
} else {
fRequest.done();
}
}
});
return Status.OK_STATUS;
}
}
public boolean execute(final IDebugCommandRequest request) {
if (request.getElements().length != 1) {
request.done();
return false;
}
Object element = request.getElements()[0];
if (!(element instanceof IDMVMContext)) {
request.done();
return false;
}
final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(((IDMVMContext)element).getDMContext(),
IContainerDMContext.class);
fExecutor.submit(new DsfRunnable() {
public void run() {
final IGDBControl gdbControl = fTracker.getService(IGDBControl.class);
if (gdbControl != null) {
gdbControl.initInferiorInputOutput(new RequestMonitor(fExecutor, null) {
@Override
protected void handleCompleted() {
if (isSuccess()) {
gdbControl.createInferiorProcess();
// Update the launch outside the executor.
// Also, we must have created the new inferior first to create
// the new streams.
// Finally, we should only do the actual restart after
// we have updated the launch, to make sure our consoles
// are ready to process any output from the new inferior (bug 223154)
new UpdateLaunchJob(request).schedule();
} else {
request.done();
}
}
});
} else {
request.done();
}
@SuppressWarnings("unchecked")
public void run() {
IGDBProcesses procService = fTracker.getService(IGDBProcesses.class);
if (procService != null) {
Map<String, Object> attributes = null;
try {
attributes = fLaunch.getLaunchConfiguration().getAttributes();
} catch (CoreException e) {}
procService.restart(containerDmc, attributes,
new DataRequestMonitor<IContainerDMContext>(fExecutor, null) {
@Override
protected void handleCompleted() {
request.done();
};
});
} else {
request.done();
}
}
});
return false;

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2010 Wind River Systems and others.
* Copyright (c) 2006, 2011 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
@ -37,7 +37,6 @@ import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.MIProcesses;
import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
@ -94,6 +93,15 @@ public class GdbLaunch extends DsfLaunch
public void initialize()
{
/*
* Registering the launch as an adapter. This ensures that this launch
* will be associated with all DMContexts from this session.
* We do this here because we want to have access to the launch even
* if we run headless, but when we run headless, GdbAdapterFactory is
* not initialized.
*/
fSession.registerModelAdapter(ILaunch.class, this);
Runnable initRunnable = new DsfRunnable() {
public void run() {
fTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSession.getId());
@ -145,34 +153,6 @@ public class GdbLaunch extends DsfLaunch
}
public DsfSession getSession() { return fSession; }
@ThreadSafeAndProhibitedFromDsfExecutor("getDsfExecutor()")
public void addInferiorProcess(String label) throws CoreException {
try {
// Add the "inferior" process object to the launch.
MIInferiorProcess inferiorProc =
getDsfExecutor().submit( new Callable<MIInferiorProcess>() {
public MIInferiorProcess call() throws CoreException {
IGDBControl gdb = fTracker.getService(IGDBControl.class);
if (gdb != null) {
return gdb.getInferiorProcess();
}
return null;
}
}).get();
IProcess inferior = DebugPlugin.newProcess(this, inferiorProc, label);
// Register the model adapter so that the inferior console becomes visible
// when we select a debug context for this debug session.
getSession().registerModelAdapter(IProcess.class, inferior);
} catch (InterruptedException e) {
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$
} catch (ExecutionException e) {
throw (CoreException)e.getCause();
} catch (RejectedExecutionException e) {
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$
}
}
@ThreadSafeAndProhibitedFromDsfExecutor("getDsfExecutor()")
public void addCLIProcess(String label) throws CoreException {

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2010 QNX Software Systems and others.
* Copyright (c) 2008, 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
@ -175,11 +175,8 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate2
// through an ICommandControlShutdownDMEvent
launch.initializeControl();
// Add the CLI and "inferior" process objects to the launch.
// Add the GDB process object to the launch.
launch.addCLIProcess("gdb"); //$NON-NLS-1$
if (!attach && sessionType != SessionType.CORE) {
launch.addInferiorProcess(exePath.lastSegment());
}
monitor.worked(1);

View file

@ -34,6 +34,7 @@ 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.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.launching.GDBProcess;
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;
@ -53,6 +54,9 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
import org.osgi.framework.BundleContext;
@ -398,12 +402,54 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
startOrRestart(containerDmc, attributes, false, rm);
}
/**
* @since 4.0
*/
protected void createConsole(final boolean restart, final RequestMonitor rm) {
fGdb.initInferiorInputOutput(new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
fGdb.createInferiorProcess();
final Process inferior = fGdb.getInferiorProcess();
final String label = fBackend.getProgramPath().lastSegment();
final ILaunch launch = (ILaunch)getSession().getModelAdapter(ILaunch.class);
// Add the inferior to the launch.
// This cannot be done on the executor or things deadlock.
DebugPlugin.getDefault().asyncExec(new Runnable() {
public void run() {
if (restart) {
// For a restart, remove the old inferior
IProcess[] launchProcesses = launch.getProcesses();
for (IProcess p : launchProcesses) {
// We know there is only one inferior, so just find it.
if ((p instanceof GDBProcess) == false) {
launch.removeProcess(p);
break;
}
}
}
// Add the inferior
IProcess process = DebugPlugin.newProcess(launch, inferior, label);
// Register as an IProcess so that the console is brought to the front
// when the inferior is selected
getSession().registerModelAdapter(IProcess.class, process);
rm.done();
}
});
}
});
}
/**
* Insert breakpoint at entry if set, and start or restart the program.
*
* @since 4.0
*/
protected void startOrRestart(final IContainerDMContext containerDmc, Map<String, Object> attributes,
protected void startOrRestart(final IContainerDMContext containerDmc, final Map<String, Object> attributes,
boolean restart, final DataRequestMonitor<IContainerDMContext> requestMonitor) {
if (fBackend.getIsAttachSession()) {
// When attaching to a running process, we do not need to set a breakpoint or
@ -412,6 +458,10 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
requestMonitor.done();
return;
}
createConsole(restart, new RequestMonitor(ImmediateExecutor.getInstance(), requestMonitor) {
@Override
protected void handleSuccess() {
final DataRequestMonitor<MIInfo> execMonitor = new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor) {
@Override
@ -458,6 +508,8 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
}
});
}
}
});
}
/**

View file

@ -35,8 +35,12 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
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;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
/**
* This class causes a process to start (run for the first time), or to
@ -49,6 +53,8 @@ import org.eclipse.core.runtime.Status;
*/
public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
private static final String GROUP_ATTR = GdbPlugin.PLUGIN_ID + "groupId"; //$NON-NLS-1$
private IGDBControl fCommandControl;
private CommandFactory fCommandFactory;
private IGDBProcesses fProcService;
@ -137,6 +143,7 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
"stepInitializeBaseSequence", //$NON-NLS-1$
"stepInsertStopOnMainBreakpoint", //$NON-NLS-1$
"stepSetBreakpointForReverse", //$NON-NLS-1$
"stepCreateConsole", //$NON-NLS-1$
"stepRunProgram", //$NON-NLS-1$
"stepSetReverseOff", //$NON-NLS-1$
"stepEnableReverse", //$NON-NLS-1$
@ -255,6 +262,57 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
}
}
/**
* Before running the program, we must create its console for IO.
*/
@Execute
public void stepCreateConsole(final RequestMonitor rm) {
fCommandControl.initInferiorInputOutput(new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
fCommandControl.createInferiorProcess();
final Process inferior = fCommandControl.getInferiorProcess();
final ILaunch launch = (ILaunch)getContainerContext().getAdapter(ILaunch.class);
final String groupId = ((IMIContainerDMContext)getContainerContext()).getGroupId();
final DsfSession session = fCommandControl.getSession();
IGDBBackend backend = fTracker.getService(IGDBBackend.class);
final String pathLabel = backend.getProgramPath().lastSegment();
// Add the inferior to the launch.
// This cannot be done on the executor or things deadlock.
DebugPlugin.getDefault().asyncExec(new Runnable() {
public void run() {
String label = pathLabel;
if (fRestart) {
// For a restart, remove the old inferior
IProcess[] launchProcesses = launch.getProcesses();
for (IProcess process : launchProcesses) {
String groupAttribute = process.getAttribute(GROUP_ATTR);
if (groupId.equals(groupAttribute)) {
launch.removeProcess(process);
// Use the exact same label as before
label = process.getLabel();
break;
}
}
}
// Add the inferior
IProcess process = DebugPlugin.newProcess(launch, inferior, label);
process.setAttribute(GROUP_ATTR, groupId);
// Register as an IProcess so that the console is brought to the front
// when the inferior is selected
session.registerModelAdapter(IProcess.class, process);
rm.done();
}
});
}
});
}
/**
* Now, run the program.
*/

View file

@ -136,7 +136,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
final Sequence.Step[] initializeSteps = new Sequence.Step[] {
new CommandMonitoringStep(InitializationShutdownStep.Direction.INITIALIZING),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.INITIALIZING),
new CommandProcessorsStep(InitializationShutdownStep.Direction.INITIALIZING),
new RegisterStep(InitializationShutdownStep.Direction.INITIALIZING),
};
@ -152,7 +151,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
final Sequence.Step[] shutdownSteps = new Sequence.Step[] {
new RegisterStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new CommandProcessorsStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new CommandMonitoringStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
};
Sequence shutdownSequence =
@ -402,20 +400,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
}
}
protected class InferiorInputOutputInitStep extends InitializationShutdownStep {
InferiorInputOutputInitStep(Direction direction) { super(direction); }
@Override
protected void initialize(final RequestMonitor requestMonitor) {
initInferiorInputOutput(requestMonitor);
}
@Override
protected void shutdown(RequestMonitor requestMonitor) {
requestMonitor.done();
}
}
protected class CommandProcessorsStep extends InitializationShutdownStep {
CommandProcessorsStep(Direction direction) { super(direction); }

View file

@ -139,7 +139,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
final Sequence.Step[] initializeSteps = new Sequence.Step[] {
new CommandMonitoringStep(InitializationShutdownStep.Direction.INITIALIZING),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.INITIALIZING),
new CommandProcessorsStep(InitializationShutdownStep.Direction.INITIALIZING),
new ListFeaturesStep(InitializationShutdownStep.Direction.INITIALIZING),
new RegisterStep(InitializationShutdownStep.Direction.INITIALIZING),
@ -157,7 +156,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
new RegisterStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new ListFeaturesStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new CommandProcessorsStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new CommandMonitoringStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
};
Sequence shutdownSequence =
@ -450,20 +448,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
requestMonitor.done();
}
}
protected class InferiorInputOutputInitStep extends InitializationShutdownStep {
InferiorInputOutputInitStep(Direction direction) { super(direction); }
@Override
protected void initialize(final RequestMonitor requestMonitor) {
initInferiorInputOutput(requestMonitor);
}
@Override
protected void shutdown(RequestMonitor requestMonitor) {
requestMonitor.done();
}
}
protected class CommandProcessorsStep extends InitializationShutdownStep {
CommandProcessorsStep(Direction direction) { super(direction); }

View file

@ -22,7 +22,6 @@ import junit.framework.Assert;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
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.ThreadSafeAndProhibitedFromDsfExecutor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
@ -622,21 +621,15 @@ public class SyncUtil {
// Perform the restart
Query<IContainerDMContext> query2 = new Query<IContainerDMContext>() {
@SuppressWarnings("unchecked")
@Override
protected void execute(final DataRequestMonitor<IContainerDMContext> rm) {
fGdbControl.initInferiorInputOutput(new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
@SuppressWarnings("unchecked")
@Override
protected void handleSuccess() {
fGdbControl.createInferiorProcess();
Map<String, Object> attributes = null;
try {
attributes = launch.getLaunchConfiguration().getAttributes();
} catch (CoreException e) {}
fProcessesService.restart(containerDmc, attributes, rm);
}
});
Map<String, Object> attributes = null;
try {
attributes = launch.getLaunchConfiguration().getAttributes();
} catch (CoreException e) {}
fProcessesService.restart(containerDmc, attributes, rm);
}
};