1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-08 18:26:01 +02:00

Bug 237308: Support for multiple inferior processes

This commit is contained in:
Marc Khouzam 2011-03-10 01:51:17 +00:00
parent 0e149f27ae
commit bcb875257f
12 changed files with 251 additions and 416 deletions

View file

@ -10,6 +10,7 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service; package org.eclipse.cdt.dsf.gdb.service;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Map; import java.util.Map;
@ -54,6 +55,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
@ -88,6 +90,12 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
// processes that are running // processes that are running
private Map<Integer, String> fProcessNames = new HashMap<Integer, String>(); private Map<Integer, String> fProcessNames = new HashMap<Integer, String>();
// Id of our process. Currently, we only know it for an attach session.
private String fProcId;
// If we can use a PTY, we store it here
private PTY fPty;
public GDBProcesses(DsfSession session) { public GDBProcesses(DsfSession session) {
super(session); super(session);
} }
@ -150,6 +158,18 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
return new GDBContainerDMC(getSession().getId(), processDmc, groupId); return new GDBContainerDMC(getSession().getId(), processDmc, groupId);
} }
/** @since 4.0 */
@Override
public IMIContainerDMContext createContainerContextFromGroupId(ICommandControlDMContext controlDmc, String groupId) {
IProcessDMContext processDmc;
if (fProcId != null) {
processDmc = createProcessContext(controlDmc, fProcId);
} else {
processDmc = createProcessContext(controlDmc, groupId);
}
return createContainerContext(processDmc, groupId);
}
@Override @Override
public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm) { public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm) {
if (dmc instanceof IMIProcessDMContext) { if (dmc instanceof IMIProcessDMContext) {
@ -159,10 +179,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
// inside the context, so must find it another way. Note that this method is also called to find the name // inside the context, so must find it another way. Note that this method is also called to find the name
// of processes to attach to, and in this case, we do have the proper pid. // of processes to attach to, and in this case, we do have the proper pid.
if (pidStr == null || pidStr.length() == 0) { if (pidStr == null || pidStr.length() == 0) {
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); pidStr = fProcId;
if (inferiorProcess != null) {
pidStr = inferiorProcess.getPid();
}
} }
int pid = -1; int pid = -1;
try { try {
@ -173,22 +190,19 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
String name = fProcessNames.get(pid); String name = fProcessNames.get(pid);
if (name == null) { if (name == null) {
// Hm. Strange. But if the pid is our inferior's, we can just use the binary name // Hm. Strange. But if the pid is our inferior's, we can just use the binary name
MIInferiorProcess inferior = fGdb.getInferiorProcess(); if (fProcId != null && Integer.parseInt(fProcId) == pid) {
if (inferior != null) {
String inferiorPidStr = inferior.getPid();
if (inferiorPidStr != null && Integer.parseInt(inferiorPidStr) == pid) {
name = fBackend.getProgramPath().lastSegment(); name = fBackend.getProgramPath().lastSegment();
} }
} }
}
if (name == null) { if (name == null) {
// This could happen if a process has terminated but the // This could happen if a process has terminated but the
// debug session is not terminated because the preference // debug session is not terminated because the preference
// to keep GDB running has been selected. // to keep GDB running has been selected.
name = "Unknown name"; //$NON-NLS-1$ name = "Unknown name"; //$NON-NLS-1$
// Until bug 305385 is fixed, the above code will not work, so we assume we // Until bug 305385 is fixed, the above code will not work, because
// are looking for our own process // we don't know the pid of our process unless we are in an attach session
// Therefore, we assume we are looking for our own process
name = fBackend.getProgramPath().lastSegment(); name = fBackend.getProgramPath().lastSegment();
} }
@ -225,12 +239,8 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
new DataRequestMonitor<IDMContext>(ImmediateExecutor.getInstance(), rm) { new DataRequestMonitor<IDMContext>(ImmediateExecutor.getInstance(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); // For an attach, we actually know the pid, so let's remember it
if (inferiorProcess != null) { fProcId = ((IMIProcessDMContext)procCtx).getProcId();
inferiorProcess.setContainerContext(containerDmc);
inferiorProcess.setPid(((IMIProcessDMContext)procCtx).getProcId());
}
IDMContext containerDmc = getData(); IDMContext containerDmc = getData();
rm.setData(containerDmc); rm.setData(containerDmc);
@ -274,11 +284,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
new RequestMonitor(getExecutor(), rm) { new RequestMonitor(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); fProcId = null;
if (inferiorProcess != null) {
inferiorProcess.setPid(null);
}
rm.done(); rm.done();
} }
}); });
@ -303,11 +309,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
@Override @Override
public void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm) { public void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm) {
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); if (fConnected) {
if (fConnected &&
inferiorProcess != null &&
inferiorProcess.getState() != MIInferiorProcess.State.TERMINATED) {
super.getProcessesBeingDebugged(dmc, rm); super.getProcessesBeingDebugged(dmc, rm);
} else { } else {
rm.setData(new IDMContext[0]); rm.setData(new IDMContext[0]);
@ -441,16 +443,57 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
startOrRestart(containerDmc, attributes, false, rm); startOrRestart(containerDmc, attributes, false, rm);
} }
/**
* This method does the necessary work to setup the input/output streams for the
* inferior process, by either preparing the PTY to be used, to simply leaving
* the PTY null, which indicates that the input/output streams of the CLI should
* be used instead; this decision is based on the type of session.
*
* @since 4.0
*/
public void initializeInputOutput(IContainerDMContext containerDmc, final RequestMonitor rm) {
if (fBackend.getSessionType() == SessionType.REMOTE || fBackend.getIsAttachSession()) {
// These types do not use a PTY
fPty = null;
rm.done();
} else {
// These types always use a PTY
try {
fPty = new PTY();
// Tell GDB to use this PTY
fGdb.queueCommand(
fCommandFactory.createMIInferiorTTYSet((IMIContainerDMContext)containerDmc, fPty.getSlaveName()),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleFailure() {
// We were not able to tell GDB to use the PTY
// so we won't use it at all.
fPty = null;
rm.done();
}
});
} catch (IOException e) {
fPty = null;
rm.done();
}
}
}
/** /**
* @since 4.0 * @since 4.0
*/ */
protected void createConsole(final IContainerDMContext containerDmc, 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) { initializeInputOutput(containerDmc, new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
fGdb.createInferiorProcess(); Process inferiorProcess;
final MIInferiorProcess inferior = fGdb.getInferiorProcess(); if (fPty == null) {
inferior.setContainerContext(containerDmc); inferiorProcess = new MIInferiorProcess(containerDmc, fBackend.getMIOutputStream());
} else {
inferiorProcess = new MIInferiorProcess(containerDmc, fPty);
}
final Process inferior = inferiorProcess;
final String label = fBackend.getProgramPath().lastSegment(); final String label = fBackend.getProgramPath().lastSegment();
final ILaunch launch = (ILaunch)getSession().getModelAdapter(ILaunch.class); final ILaunch launch = (ILaunch)getSession().getModelAdapter(ILaunch.class);

View file

@ -62,7 +62,6 @@ import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager; import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager;
import org.eclipse.cdt.dsf.mi.service.MIProcesses; 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.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadGroupCreatedEvent; 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.events.MIThreadGroupExitedEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIConst; import org.eclipse.cdt.dsf.mi.service.command.output.MIConst;
@ -602,6 +601,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
// In such a case, we choose the first process we find // In such a case, we choose the first process we find
// This works when we run a single process // This works when we run a single process
// but will break for multi-process!!! // but will break for multi-process!!!
// khouzam
if (getThreadToGroupMap().isEmpty()) { if (getThreadToGroupMap().isEmpty()) {
groupId = MIProcesses.UNIQUE_GROUP_ID; groupId = MIProcesses.UNIQUE_GROUP_ID;
} else { } else {
@ -618,6 +618,18 @@ public class GDBProcesses_7_0 extends AbstractDsfService
/** @since 4.0 */ /** @since 4.0 */
public IMIContainerDMContext createContainerContextFromGroupId(ICommandControlDMContext controlDmc, String groupId) { public IMIContainerDMContext createContainerContextFromGroupId(ICommandControlDMContext controlDmc, String groupId) {
if (groupId == null || groupId.length() == 0) {
// This happens when we are doing non-attach, so for GDB < 7.2, we know that in that case
// we are single process, so lets see if we have the group in our map.
assert getGroupToPidMap().size() <= 1 : "More than one process in our map"; //$NON-NLS-1$
if (getGroupToPidMap().size() == 1) {
for (String key : getGroupToPidMap().keySet()) {
groupId = key;
break;
}
}
}
String pid = getGroupToPidMap().get(groupId); String pid = getGroupToPidMap().get(groupId);
if (pid == null) { if (pid == null) {
pid = groupId; pid = groupId;
@ -800,12 +812,6 @@ public class GDBProcesses_7_0 extends AbstractDsfService
// By now, GDB has reported the groupId that was created for this process // By now, GDB has reported the groupId that was created for this process
fContainerDmc = createContainerContext(procCtx, getGroupFromPid(((IMIProcessDMContext)procCtx).getProcId())); fContainerDmc = createContainerContext(procCtx, getGroupFromPid(((IMIProcessDMContext)procCtx).getProcId()));
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. // Store the fully formed container context so it can be returned to the caller.
dataRm.setData(fContainerDmc); dataRm.setData(fContainerDmc);
@ -873,13 +879,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
fCommandControl.queueCommand( fCommandControl.queueCommand(
fCommandFactory.createMITargetDetach(controlDmc, procDmc.getProcId()), 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 { } else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$
rm.done(); rm.done();

View file

@ -29,9 +29,9 @@ import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl2; import org.eclipse.cdt.dsf.debug.service.IRunControl2;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; 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.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.IMIRunControl; import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.MIRunControl; import org.eclipse.cdt.dsf.mi.service.MIRunControl;
@ -77,7 +77,6 @@ public class GDBRunControl extends MIRunControl {
private IGDBBackend fGdb; private IGDBBackend fGdb;
private IMIProcesses fProcService; private IMIProcesses fProcService;
private IGDBControl fGbControlService;
private CommandFactory fCommandFactory; private CommandFactory fCommandFactory;
// Record list of execution contexts // Record list of execution contexts
@ -104,7 +103,6 @@ public class GDBRunControl extends MIRunControl {
fGdb = getServicesTracker().getService(IGDBBackend.class); fGdb = getServicesTracker().getService(IGDBBackend.class);
fProcService = getServicesTracker().getService(IMIProcesses.class); fProcService = getServicesTracker().getService(IMIProcesses.class);
fGbControlService = getServicesTracker().getService(IGDBControl.class);
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
register(new String[]{IRunControl.class.getName(), register(new String[]{IRunControl.class.getName(),
@ -135,7 +133,7 @@ public class GDBRunControl extends MIRunControl {
} }
@Override @Override
public void suspend(IExecutionDMContext context, final RequestMonitor rm){ public void suspend(final IExecutionDMContext context, final RequestMonitor rm){
canSuspend( canSuspend(
context, context,
new DataRequestMonitor<Boolean>(getExecutor(), rm) { new DataRequestMonitor<Boolean>(getExecutor(), rm) {
@ -151,7 +149,8 @@ public class GDBRunControl extends MIRunControl {
if (fGdb.getIsAttachSession() if (fGdb.getIsAttachSession()
&& fGdb.getSessionType() != SessionType.REMOTE && fGdb.getSessionType() != SessionType.REMOTE
&& Platform.getOS().equals(Platform.OS_WIN32)) { && Platform.getOS().equals(Platform.OS_WIN32)) {
String inferiorPid = fGbControlService.getInferiorProcess().getPid(); IMIProcessDMContext processDmc = DMContexts.getAncestorOfType(context, IMIProcessDMContext.class);
String inferiorPid = processDmc.getProcId();
if (inferiorPid != null) { if (inferiorPid != null) {
fGdb.interruptInferiorAndWait(Long.parseLong(inferiorPid), IGDBBackend.INTERRUPT_TIMEOUT_DEFAULT, rm); fGdb.interruptInferiorAndWait(Long.parseLong(inferiorPid), IGDBBackend.INTERRUPT_TIMEOUT_DEFAULT, rm);
} }

View file

@ -10,6 +10,7 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service; package org.eclipse.cdt.dsf.gdb.service;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -32,13 +33,13 @@ import org.eclipse.cdt.dsf.gdb.launching.InferiorRuntimeProcess;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; 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.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; 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.MIBreakpoint;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServicesTracker; 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.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.DebugPlugin;
@ -60,6 +61,7 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
private CommandFactory fCommandFactory; private CommandFactory fCommandFactory;
private IGDBProcesses fProcService; private IGDBProcesses fProcService;
private IReverseRunControl fReverseService; private IReverseRunControl fReverseService;
private IGDBBackend fBackend;
private DsfServicesTracker fTracker; private DsfServicesTracker fTracker;
@ -82,6 +84,8 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
// Indicates if the sequence is being used for a restart or a start // Indicates if the sequence is being used for a restart or a start
private final boolean fRestart; private final boolean fRestart;
private PTY fPty;
// Store the dataRM so that we can fill it with the new container context, which we must return // Store the dataRM so that we can fill it with the new container context, which we must return
// Although we can access this through Sequence.getRequestMonitor(), we would loose the type-checking. // Although we can access this through Sequence.getRequestMonitor(), we would loose the type-checking.
// Therefore, doing it like this is more future-proof. // Therefore, doing it like this is more future-proof.
@ -144,6 +148,7 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
"stepInitializeBaseSequence", //$NON-NLS-1$ "stepInitializeBaseSequence", //$NON-NLS-1$
"stepInsertStopOnMainBreakpoint", //$NON-NLS-1$ "stepInsertStopOnMainBreakpoint", //$NON-NLS-1$
"stepSetBreakpointForReverse", //$NON-NLS-1$ "stepSetBreakpointForReverse", //$NON-NLS-1$
"stepInitializeInputOutput", //$NON-NLS-1$
"stepCreateConsole", //$NON-NLS-1$ "stepCreateConsole", //$NON-NLS-1$
"stepRunProgram", //$NON-NLS-1$ "stepRunProgram", //$NON-NLS-1$
"stepSetReverseOff", //$NON-NLS-1$ "stepSetReverseOff", //$NON-NLS-1$
@ -166,6 +171,7 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
fCommandControl = fTracker.getService(IGDBControl.class); fCommandControl = fTracker.getService(IGDBControl.class);
fCommandFactory = fTracker.getService(IMICommandControl.class).getCommandFactory(); fCommandFactory = fTracker.getService(IMICommandControl.class).getCommandFactory();
fProcService = fTracker.getService(IGDBProcesses.class); fProcService = fTracker.getService(IGDBProcesses.class);
fBackend = fTracker.getService(IGDBBackend.class);
if (fCommandControl == null || fCommandFactory == null || fProcService == null) { if (fCommandControl == null || fCommandFactory == null || fProcService == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Cannot obtain service", null)); //$NON-NLS-1$ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Cannot obtain service", null)); //$NON-NLS-1$
@ -263,20 +269,57 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
} }
} }
/**
* This method does the necessary work to setup the input/output streams for the
* inferior process, by either preparing the PTY to be used, to simply leaving
* the PTY null, which indicates that the input/output streams of the CLI should
* be used instead; this decision is based on the type of session.
*/
@Execute
public void stepInitializeInputOutput(final RequestMonitor rm) {
if (fBackend.getSessionType() == SessionType.REMOTE || fBackend.getIsAttachSession()) {
// These types do not use a PTY
fPty = null;
rm.done();
} else {
// These types always use a PTY
try {
fPty = new PTY();
// Tell GDB to use this PTY
fCommandControl.queueCommand(
fCommandFactory.createMIInferiorTTYSet((IMIContainerDMContext)getContainerContext(), fPty.getSlaveName()),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleFailure() {
// We were not able to tell GDB to use the PTY
// so we won't use it at all.
fPty = null;
rm.done();
}
});
} catch (IOException e) {
fPty = null;
rm.done();
}
}
}
/** /**
* Before running the program, we must create its console for IO. * Before running the program, we must create its console for IO.
*/ */
@Execute @Execute
public void stepCreateConsole(final RequestMonitor rm) { public void stepCreateConsole(final RequestMonitor rm) {
fCommandControl.initInferiorInputOutput(new RequestMonitor(ImmediateExecutor.getInstance(), rm) { Process inferiorProcess;
@Override if (fPty == null) {
protected void handleSuccess() { inferiorProcess = new MIInferiorProcess(fContainerDmc, fBackend.getMIOutputStream());
fCommandControl.createInferiorProcess(); } else {
final Process inferior = fCommandControl.getInferiorProcess(); inferiorProcess = new MIInferiorProcess(fContainerDmc, fPty);
}
final Process inferior = inferiorProcess;
final ILaunch launch = (ILaunch)getContainerContext().getAdapter(ILaunch.class); final ILaunch launch = (ILaunch)getContainerContext().getAdapter(ILaunch.class);
final String groupId = ((IMIContainerDMContext)getContainerContext()).getGroupId(); final String groupId = ((IMIContainerDMContext)getContainerContext()).getGroupId();
final DsfSession session = fCommandControl.getSession();
IGDBBackend backend = fTracker.getService(IGDBBackend.class); IGDBBackend backend = fTracker.getService(IGDBBackend.class);
final String pathLabel = backend.getProgramPath().lastSegment(); final String pathLabel = backend.getProgramPath().lastSegment();
@ -309,8 +352,6 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
} }
}); });
} }
});
}
/** /**
* Now, run the program. * Now, run the program.
@ -329,13 +370,8 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
// Now that the process is started, the pid has been allocated // Now that the process is started, the pid has been allocated
// so we need to fetch the proper container context // so we need to fetch the proper container context
// We replace our current context which does not have the pid, with one that has the pid. // We replace our current context which does not have the pid, with one that has the pid.
if (fContainerDmc instanceof IMIContainerDMContext) { if (fContainerDmc instanceof IMIContainerDMContext) {
fContainerDmc = fProcService.createContainerContextFromGroupId(fCommandControl.getContext(), ((IMIContainerDMContext)fContainerDmc).getGroupId()); 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 // This is the container context that this sequence is supposed to return: set the dataRm
fDataRequestMonitor.setData(fContainerDmc); fDataRequestMonitor.setData(fContainerDmc);

View file

@ -39,7 +39,6 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.launching.FinalLaunchSequence; import org.eclipse.cdt.dsf.gdb.launching.FinalLaunchSequence;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; 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;
import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent; import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
@ -49,12 +48,10 @@ import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl;
import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor; import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext; import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor; import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor;
@ -101,9 +98,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
private MIRunControlEventProcessor fMIEventProcessor; private MIRunControlEventProcessor fMIEventProcessor;
private CLIEventProcessor fCLICommandProcessor; private CLIEventProcessor fCLICommandProcessor;
private AbstractCLIProcess fCLIProcess; private AbstractCLIProcess fCLIProcess;
private MIInferiorProcess fInferiorProcess;
private PTY fPty;
/** /**
* @since 3.0 * @since 3.0
@ -226,50 +220,11 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
); );
} }
/*
* This method does the necessary work to setup the input/output streams for the
* inferior process, by either preparing the PTY to be used, to simply leaving
* the PTY null, which indicates that the input/output streams of the CLI should
* be used instead; this decision is based on the type of session.
*/
public void initInferiorInputOutput(final RequestMonitor requestMonitor) {
if (fMIBackend.getSessionType() == SessionType.REMOTE || fMIBackend.getIsAttachSession()) {
// These types do not use a PTY
fPty = null;
requestMonitor.done();
} else {
// These types always use a PTY
try {
fPty = new PTY();
// Tell GDB to use this PTY
queueCommand(
getCommandFactory().createMIInferiorTTYSet(fControlDmc, fPty.getSlaveName()),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor) {
@Override
protected void handleFailure() {
// We were not able to tell GDB to use the PTY
// so we won't use it at all.
fPty = null;
requestMonitor.done();
}
});
} catch (IOException e) {
fPty = null;
requestMonitor.done();
}
}
}
/* /*
* This method creates a new inferior process object based on the current Pty or output stream. * This method creates a new inferior process object based on the current Pty or output stream.
*/ */
public void createInferiorProcess() { private void createInferiorProcess() {
if (fPty == null) { // khouzam BROKEN because no one does the below when we restart
fInferiorProcess = new MIInferiorProcess(GDBControl.this, fMIBackend.getMIOutputStream());
} else {
fInferiorProcess = new MIInferiorProcess(GDBControl.this, fPty);
}
// Create the CLI event processor each time this method is called // Create the CLI event processor each time this method is called
// to reset the internal thread id count // to reset the internal thread id count
@ -284,10 +239,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
return fCLIProcess; return fCLIProcess;
} }
public MIInferiorProcess getInferiorProcess() {
return fInferiorProcess;
}
/** /**
* @since 2.0 * @since 2.0
*/ */
@ -438,8 +389,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
return; return;
} }
createInferiorProcess(); fCLICommandProcessor = new CLIEventProcessor(GDBControl.this, fControlDmc);
fMIEventProcessor = new MIRunControlEventProcessor(GDBControl.this, fControlDmc); fMIEventProcessor = new MIRunControlEventProcessor(GDBControl.this, fControlDmc);
requestMonitor.done(); requestMonitor.done();
@ -450,7 +400,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
fCLICommandProcessor.dispose(); fCLICommandProcessor.dispose();
fMIEventProcessor.dispose(); fMIEventProcessor.dispose();
fCLIProcess.dispose(); fCLIProcess.dispose();
fInferiorProcess.dispose();
requestMonitor.done(); requestMonitor.done();
} }

View file

@ -40,7 +40,6 @@ import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.launching.FinalLaunchSequence; import org.eclipse.cdt.dsf.gdb.launching.FinalLaunchSequence;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent;
import org.eclipse.cdt.dsf.gdb.service.SessionType;
import org.eclipse.cdt.dsf.mi.service.IMIBackend; import org.eclipse.cdt.dsf.mi.service.IMIBackend;
import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent; import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
@ -50,13 +49,11 @@ import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl;
import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor_7_0; import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor_7_0;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext; import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor_7_0; import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor_7_0;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIListFeaturesInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIListFeaturesInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor;
@ -103,9 +100,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
private MIRunControlEventProcessor_7_0 fMIEventProcessor; private MIRunControlEventProcessor_7_0 fMIEventProcessor;
private CLIEventProcessor_7_0 fCLICommandProcessor; private CLIEventProcessor_7_0 fCLICommandProcessor;
private AbstractCLIProcess fCLIProcess; private AbstractCLIProcess fCLIProcess;
private MIInferiorProcess fInferiorProcess = null;
private PTY fPty;
private List<String> fFeatures = new ArrayList<String>(); private List<String> fFeatures = new ArrayList<String>();
/** /**
@ -242,60 +237,10 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
}); });
} }
/*
* This method does the necessary work to setup the input/output streams for the
* inferior process, by either preparing the PTY to be used, to simply leaving
* the PTY null, which indicates that the input/output streams of the CLI should
* be used instead; this decision is based on the type of session.
*/
public void initInferiorInputOutput(final RequestMonitor requestMonitor) {
if (fMIBackend.getSessionType() == SessionType.REMOTE || fMIBackend.getIsAttachSession()) {
// These types do not use a PTY
fPty = null;
requestMonitor.done();
} else {
// These types always use a PTY
try {
fPty = new PTY();
// Tell GDB to use this PTY
queueCommand(
getCommandFactory().createMIInferiorTTYSet(fControlDmc, fPty.getSlaveName()),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor) {
@Override
protected void handleFailure() {
// We were not able to tell GDB to use the PTY
// so we won't use it at all.
fPty = null;
requestMonitor.done();
}
});
} catch (IOException e) {
fPty = null;
requestMonitor.done();
}
}
}
/**
* This method creates a new inferior process object based on the current Pty or output stream.
*/
public void createInferiorProcess() {
if (fPty == null) {
fInferiorProcess = new MIInferiorProcess(GDBControl_7_0.this, fMIBackend.getMIOutputStream());
} else {
fInferiorProcess = new MIInferiorProcess(GDBControl_7_0.this, fPty);
}
}
public AbstractCLIProcess getCLIProcess() { public AbstractCLIProcess getCLIProcess() {
return fCLIProcess; return fCLIProcess;
} }
public MIInferiorProcess getInferiorProcess() {
return fInferiorProcess;
}
/** /**
* @since 2.0 * @since 2.0
*/ */
@ -468,8 +413,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
return; return;
} }
createInferiorProcess();
fCLICommandProcessor = new CLIEventProcessor_7_0(GDBControl_7_0.this, fControlDmc); fCLICommandProcessor = new CLIEventProcessor_7_0(GDBControl_7_0.this, fControlDmc);
fMIEventProcessor = new MIRunControlEventProcessor_7_0(GDBControl_7_0.this, fControlDmc); fMIEventProcessor = new MIRunControlEventProcessor_7_0(GDBControl_7_0.this, fControlDmc);
@ -481,7 +424,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
fCLICommandProcessor.dispose(); fCLICommandProcessor.dispose();
fMIEventProcessor.dispose(); fMIEventProcessor.dispose();
fCLIProcess.dispose(); fCLIProcess.dispose();
fInferiorProcess.dispose();
requestMonitor.done(); requestMonitor.done();
} }

View file

@ -19,19 +19,17 @@ import java.util.Properties;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess; import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess;
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
public interface IGDBControl extends IMICommandControl { public interface IGDBControl extends IMICommandControl {
void terminate(final RequestMonitor rm);
void initInferiorInputOutput(final RequestMonitor requestMonitor);
void createInferiorProcess();
AbstractCLIProcess getCLIProcess(); AbstractCLIProcess getCLIProcess();
MIInferiorProcess getInferiorProcess(); /**
* Request to terminate GDB.
*
* @param rm The requestMonitor indicating that GDB has been terminated.
*/
void terminate(RequestMonitor rm);
/** /**
* This method should be called once and only once, during the launch, * This method should be called once and only once, during the launch,
@ -39,12 +37,12 @@ public interface IGDBControl extends IMICommandControl {
* to configure GDB for the type of debugging session chosen by the * to configure GDB for the type of debugging session chosen by the
* user. * user.
* *
* @param requestMonitor The requestMonitor indicating that the * @param rm The requestMonitor indicating that the final steps if
* final steps if initialization are completed. * initialization are completed.
* *
* @since 4.0 * @since 4.0
*/ */
void completeInitialization(RequestMonitor requestMonitor); void completeInitialization(RequestMonitor rm);
/** /**
* @since 2.0 * @since 2.0

View file

@ -496,8 +496,7 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses, ICa
new DataRequestMonitor<MIInfo>(getExecutor(), rm) { new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
IMIContainerDMContext containerDmc = createContainerContext(procCtx, IMIContainerDMContext containerDmc = createContainerContext(procCtx, MIProcesses.UNIQUE_GROUP_ID);
((IMIProcessDMContext)procCtx).getProcId());
getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc), getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc),
getProperties()); getProperties());
rm.setData(containerDmc); rm.setData(containerDmc);

View file

@ -629,7 +629,8 @@ public class CommandFactory {
return new MIGDBShowExitCode(ctx); return new MIGDBShowExitCode(ctx);
} }
public ICommand<MIInfo> createMIInferiorTTYSet(ICommandControlDMContext dmc, String tty) { /** @since 4.0 */
public ICommand<MIInfo> createMIInferiorTTYSet(IMIContainerDMContext dmc, String tty) {
return new MIInferiorTTYSet(dmc, tty); return new MIInferiorTTYSet(dmc, tty);
} }

View file

@ -35,27 +35,20 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IProcesses; import org.eclipse.cdt.dsf.debug.service.IProcesses;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; 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.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent; 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.ICommandControlService.ICommandControlShutdownDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.ICommandListener; import org.eclipse.cdt.dsf.debug.service.command.ICommandListener;
import org.eclipse.cdt.dsf.debug.service.command.ICommandResult; import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
import org.eclipse.cdt.dsf.debug.service.command.ICommandToken; import org.eclipse.cdt.dsf.debug.service.command.ICommandToken;
import org.eclipse.cdt.dsf.debug.service.command.IEventListener; import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerExitedDMEvent; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLICommand; import org.eclipse.cdt.dsf.mi.service.command.commands.CLICommand;
import org.eclipse.cdt.dsf.mi.service.command.output.MIConst;
import org.eclipse.cdt.dsf.mi.service.command.output.MIExecAsyncOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIGDBShowExitCodeInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIGDBShowExitCodeInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord; import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
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.MITargetStreamOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
@ -75,7 +68,7 @@ public class MIInferiorProcess extends Process
implements IEventListener, ICommandListener implements IEventListener, ICommandListener
{ {
public enum State { RUNNING, STOPPED, TERMINATED } private boolean fTerminated;
private final OutputStream fOutputStream; private final OutputStream fOutputStream;
private final InputStream fInputStream; private final InputStream fInputStream;
@ -86,9 +79,8 @@ public class MIInferiorProcess extends Process
private final PipedOutputStream fErrorStreamPiped; private final PipedOutputStream fErrorStreamPiped;
private final DsfSession fSession; private final DsfSession fSession;
private final PTY fPty;
private final ICommandControlService fCommandControl; private final IMICommandControl fCommandControl;
private CommandFactory fCommandFactory; private CommandFactory fCommandFactory;
private IContainerDMContext fContainerDMContext; private IContainerDMContext fContainerDMContext;
@ -110,75 +102,59 @@ public class MIInferiorProcess extends Process
*/ */
private int fSuppressTargetOutputCounter = 0; private int fSuppressTargetOutputCounter = 0;
/**
* Flag we use to avoid making repeated CLI 'info program' requests to get
* the PID when gdb doesn't provide the PID in the response.
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
private boolean fGiveUpOnPidQuery;
@ThreadSafe @ThreadSafe
Integer fExitCode = null; Integer fExitCode = null;
private State fState = State.RUNNING;
@ConfinedToDsfExecutor("fSession#getExecutor")
private String fInferiorPid;
/** /**
* Creates an inferior process object which uses the given output stream * Creates an inferior process object which uses the given output stream
* to write the user standard input into. * to write the user standard input into.
* *
* @param commandControl Command control that this inferior process belongs to. * @param session The DsfSession this inferior belongs to
* @param gdbOutputStream The output stream to use to write user IO into. * @param gdbOutputStream The output stream to use to write user IO into.
* @since 1.1 * @since 4.0
*/ */
@ConfinedToDsfExecutor("fSession#getExecutor") @ConfinedToDsfExecutor("fSession#getExecutor")
public MIInferiorProcess(ICommandControlService commandControl, OutputStream gdbOutputStream) { public MIInferiorProcess(IContainerDMContext container, OutputStream gdbOutputStream) {
this(commandControl, gdbOutputStream, null); this(container, gdbOutputStream, null);
} }
/** /**
* Creates an inferior process object which uses the given terminal * Creates an inferior process object which uses the given terminal
* to write the user standard input into. * to write the user standard input into.
* *
* @param commandControl Command control that this inferior process belongs to. * @param session The DsfSession this inferior belongs to
* @param p The terminal to use to write user IO into. * @param p The terminal to use to write user IO into.
* @since 1.1 * @since 4.0
*/ */
@ConfinedToDsfExecutor("fSession#getExecutor") @ConfinedToDsfExecutor("fSession#getExecutor")
public MIInferiorProcess(ICommandControlService commandControl, PTY p) { public MIInferiorProcess(IContainerDMContext container, PTY p) {
this(commandControl, null, p); this(container, null, p);
} }
@ConfinedToDsfExecutor("fSession#getExecutor") @ConfinedToDsfExecutor("fSession#getExecutor")
private MIInferiorProcess(ICommandControlService commandControl, final OutputStream gdbOutputStream, PTY p) { private MIInferiorProcess(IContainerDMContext container, final OutputStream gdbOutputStream, PTY pty) {
fCommandControl = commandControl; fSession = DsfSession.getSession(container.getSessionId());
fSession = commandControl.getSession();
fSession.addServiceEventListener(this, null); fSession.addServiceEventListener(this, null);
if (fCommandControl instanceof IMICommandControl) { fContainerDMContext = container;
fCommandFactory = ((IMICommandControl)fCommandControl).getCommandFactory();
} else {
// Should not happen
fCommandFactory = new CommandFactory();
}
commandControl.addEventListener(this); DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSession.getId());
commandControl.addCommandListener(this); fCommandControl = tracker.getService(IMICommandControl.class);
tracker.dispose();
fPty = p; fCommandFactory = fCommandControl.getCommandFactory();
if (fPty != null) {
fOutputStream = fPty.getOutputStream(); fCommandControl.addEventListener(this);
fInputStream = fPty.getInputStream(); fCommandControl.addCommandListener(this);
if (pty != null) {
fOutputStream = pty.getOutputStream();
fInputStream = pty.getInputStream();
fInputStreamPiped = null; fInputStreamPiped = null;
} else { } else {
fOutputStream = new OutputStream() { fOutputStream = new OutputStream() {
@Override @Override
public void write(int b) throws IOException { public void write(int b) throws IOException {
if (getState() != State.RUNNING) {
throw new IOException("Target is not running"); //$NON-NLS-1$
}
gdbOutputStream.write(b); gdbOutputStream.write(b);
} }
}; };
@ -215,22 +191,11 @@ public class MIInferiorProcess extends Process
closeIO(); closeIO();
setState(State.TERMINATED); setTerminated();
fDisposed = true; fDisposed = true;
} }
@ThreadSafe
protected DsfSession getSession() {
return fSession;
}
/**
* @since 1.1
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
protected ICommandControlService getCommandControlService() { return fCommandControl; }
@ConfinedToDsfExecutor("fSession#getExecutor") @ConfinedToDsfExecutor("fSession#getExecutor")
protected boolean isDisposed() { return fDisposed; } protected boolean isDisposed() { return fDisposed; }
@ -251,9 +216,9 @@ public class MIInferiorProcess extends Process
@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor") @ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
public synchronized void waitForSync() throws InterruptedException { public synchronized void waitForSync() throws InterruptedException {
assert !getSession().getExecutor().isInExecutorThread(); assert !fSession.getExecutor().isInExecutorThread();
while (getState() != State.TERMINATED) { while (!fTerminated) {
wait(100); wait(100);
} }
} }
@ -264,7 +229,7 @@ public class MIInferiorProcess extends Process
@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor") @ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
@Override @Override
public int waitFor() throws InterruptedException { public int waitFor() throws InterruptedException {
assert !getSession().getExecutor().isInExecutorThread(); assert !fSession.getExecutor().isInExecutorThread();
waitForSync(); waitForSync();
return exitValue(); return exitValue();
@ -273,7 +238,7 @@ public class MIInferiorProcess extends Process
@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor") @ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
@Override @Override
public int exitValue() { public int exitValue() {
assert !getSession().getExecutor().isInExecutorThread(); assert !fSession.getExecutor().isInExecutorThread();
synchronized (this) { synchronized (this) {
if (fExitCode != null) { if (fExitCode != null) {
@ -295,14 +260,16 @@ public class MIInferiorProcess extends Process
if (isDisposed()) { if (isDisposed()) {
rm.setData(0); rm.setData(0);
rm.done(); rm.done();
} else if (getState() != State.TERMINATED) { } else if (!fTerminated) {
// This will cause ExecutionException to be thrown with a CoreException, // This will cause ExecutionException to be thrown with a CoreException,
// which will in turn contain the IllegalThreadStateException. // which will in turn contain the IllegalThreadStateException.
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "GDB is still running.", new IllegalThreadStateException())); //$NON-NLS-1$ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "GDB is still running.", new IllegalThreadStateException())); //$NON-NLS-1$
rm.done(); rm.done();
} else { } else {
getCommandControlService().queueCommand( // The exitCode from GDB does not seem to be handled for multi-process
fCommandFactory.createMIGDBShowExitCode(getCommandControlService().getContext()), // so there is no point is specifying the container
fCommandControl.queueCommand(
fCommandFactory.createMIGDBShowExitCode(fCommandControl.getContext()),
new DataRequestMonitor<MIGDBShowExitCodeInfo>(fSession.getExecutor(), rm) { new DataRequestMonitor<MIGDBShowExitCodeInfo>(fSession.getExecutor(), rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
@ -371,7 +338,7 @@ public class MIInferiorProcess extends Process
@ConfinedToDsfExecutor("fSession#getExecutor") @ConfinedToDsfExecutor("fSession#getExecutor")
private void doDestroy() { private void doDestroy() {
if (isDisposed() || !fSession.isActive() || getState() == State.TERMINATED) return; if (isDisposed() || !fSession.isActive() || fTerminated) return;
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSession.getId()); DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSession.getId());
IProcesses procService = tracker.getService(IProcesses.class); IProcesses procService = tracker.getService(IProcesses.class);
@ -380,35 +347,15 @@ public class MIInferiorProcess extends Process
IProcessDMContext procDmc = DMContexts.getAncestorOfType(fContainerDMContext, IProcessDMContext.class); IProcessDMContext procDmc = DMContexts.getAncestorOfType(fContainerDMContext, IProcessDMContext.class);
procService.terminate(procDmc, new RequestMonitor(ImmediateExecutor.getInstance(), null)); procService.terminate(procDmc, new RequestMonitor(ImmediateExecutor.getInstance(), null));
} else { } else {
setState(State.TERMINATED); setTerminated();
} }
} }
@ThreadSafe
public synchronized State getState() {
return fState;
}
@ConfinedToDsfExecutor("fSession#getExecutor") @ConfinedToDsfExecutor("fSession#getExecutor")
public IExecutionDMContext getExecutionContext() { private synchronized void setTerminated() {
return fContainerDMContext; if (fTerminated) return;
} fTerminated = true;
/**
* @since 1.1
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
public void setContainerContext(IContainerDMContext containerDmc) {
fContainerDMContext = containerDmc;
}
@ConfinedToDsfExecutor("fSession#getExecutor")
synchronized void setState(State state) {
if (fState == State.TERMINATED) return;
fState = state;
if (fState == State.TERMINATED) {
closeIO(); closeIO();
}
notifyAll(); notifyAll();
} }
@ -420,68 +367,9 @@ public class MIInferiorProcess extends Process
return fErrorStreamPiped; return fErrorStreamPiped;
} }
public PTY getPTY() {
return fPty;
}
/**
* Return the PID of this inferior, or null if not known.
*
* @since 1.1
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
public String getPid() {
return fInferiorPid;
}
/**
* Record the PID of this inferior. The PID may not be known at the time of
* our instantiation.
*
* @since 1.1
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
public void setPid(String pid) {
fInferiorPid = pid;
}
public void eventReceived(Object output) { public void eventReceived(Object output) {
for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) {
if (oobr instanceof MIExecAsyncOutput) { if (oobr instanceof MITargetStreamOutput) {
MIExecAsyncOutput async = (MIExecAsyncOutput)oobr;
String state = async.getAsyncClass();
if ("stopped".equals(state)) { //$NON-NLS-1$
boolean handled = false;
MIResult[] results = async.getMIResults();
for (int i = 0; i < results.length; i++) {
String var = results[i].getVariable();
if (var.equals("reason")) { //$NON-NLS-1$
MIValue value = results[i].getMIValue();
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$
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);
}
handled = true;
}
}
}
if (!handled) {
setState(State.STOPPED);
}
}
} else if (oobr instanceof MITargetStreamOutput) {
if (fSuppressTargetOutputCounter > 0) return; if (fSuppressTargetOutputCounter > 0) return;
MITargetStreamOutput tgtOut = (MITargetStreamOutput)oobr; MITargetStreamOutput tgtOut = (MITargetStreamOutput)oobr;
if (fInputStreamPiped != null && tgtOut.getString() != null) { if (fInputStreamPiped != null && tgtOut.getString() != null) {
@ -513,26 +401,6 @@ public class MIInferiorProcess extends Process
if (token.getCommand() instanceof CLICommand<?>) { if (token.getCommand() instanceof CLICommand<?>) {
fSuppressTargetOutputCounter--; fSuppressTargetOutputCounter--;
} }
MIInfo cmdResult = (MIInfo) result ;
MIOutput output = cmdResult.getMIOutput();
MIResultRecord rr = output.getMIResultRecord();
// Check if the state changed.
String state = rr.getResultClass();
if ("running".equals(state)) { setState(State.RUNNING); }//$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$
} }
/** /**
@ -540,46 +408,29 @@ public class MIInferiorProcess extends Process
*/ */
@DsfServiceEventHandler @DsfServiceEventHandler
public void eventDispatched(IExitedDMEvent e) { public void eventDispatched(IExitedDMEvent e) {
if (e.getDMContext() instanceof IContainerDMContext) { if (e.getDMContext() instanceof IMIContainerDMContext) {
setState(State.TERMINATED); // For multi-process, make sure the exited event
// is actually for this inferior.
// We must compare the groupId and not the full context
// because the container that we hold is incomplete.
String inferiorGroup = ((IMIContainerDMContext)fContainerDMContext).getGroupId();
if (inferiorGroup == null || inferiorGroup.length() == 0) {
// Single process case, so we know we have terminated
setTerminated();
} else {
String terminatedGroup = ((IMIContainerDMContext)e.getDMContext()).getGroupId();
if (inferiorGroup.equals(terminatedGroup)) {
setTerminated();
}
}
} }
} }
// /**
// Post-poned because 'info program' yields different result on different platforms. * @since 4.0
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=305385#c20 */
// @DsfServiceEventHandler
// /** public void eventDispatched(ICommandControlShutdownDMEvent e) {
// * @since 3.0 dispose();
// */ }
// @ConfinedToDsfExecutor("fSession#getExecutor")
// public void update() {
// // If we don't already know the PID of the inferior, ask GDB for it.
// if (getPid() == null && fContainerDMContext != null && !fGiveUpOnPidQuery) {
// getCommandControlService().queueCommand(
// fCommandFactory.createCLIInfoProgram(fContainerDMContext),
// new DataRequestMonitor<CLIInfoProgramInfo>(fSession.getExecutor(), null) {
// @Override
// protected void handleSuccess() {
// if (getPid() == null) { // check again
// Long pid = getData().getPID();
// if (pid != null) {
// setPid(Long.toString(pid));
// }
// else {
// // We made the 'program info' request to
// // GDB, it gave us an answer, but it either
// // doesn't provide the process PID or we
// // can't make it out. No point in trying
// // again.
// fGiveUpOnPidQuery = true;
// assert false; // investigate why this is happening
// }
// }
// }
// });
// }
// }
//
} }

View file

@ -31,6 +31,7 @@ import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.MIProcesses; import org.eclipse.cdt.dsf.mi.service.MIProcesses;
import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerExitedDMEvent;
import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerStartedDMEvent; import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerStartedDMEvent;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLICommand; import org.eclipse.cdt.dsf.mi.service.command.commands.CLICommand;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue; import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue;
@ -269,14 +270,30 @@ public class MIRunControlEventProcessor
event = MIFunctionFinishedEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); event = MIFunctionFinishedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} else if ("exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$ } else if ("exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$
event = MIInferiorExitEvent.parse(fCommandControl.getContext(), exec.getToken(), exec.getMIResults()); event = MIInferiorExitEvent.parse(fCommandControl.getContext(), exec.getToken(), exec.getMIResults());
// Until we clean up the handling of all these events, we need to send the containerExited event
// Only needed GDB < 7.0, because GDB itself does not yet send an MI event about the inferior terminating
sendContainerExitedEvent();
} else if ("exited-signalled".equals(reason)) { //$NON-NLS-1$ } else if ("exited-signalled".equals(reason)) { //$NON-NLS-1$
event = MIInferiorSignalExitEvent.parse(fCommandControl.getContext(), exec.getToken(), exec.getMIResults()); event = MIInferiorSignalExitEvent.parse(fCommandControl.getContext(), exec.getToken(), exec.getMIResults());
// Until we clean up the handling of all these events, we need to send the containerExited event
// Only needed GDB < 7.0, because GDB itself does not yet send an MI event about the inferior terminating
sendContainerExitedEvent();
} else if (STOPPED_REASON.equals(reason)) { } else if (STOPPED_REASON.equals(reason)) {
event = MIStoppedEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); event = MIStoppedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
} }
return event; return event;
} }
private void sendContainerExitedEvent() {
IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class);
if (procService != null) {
IContainerDMContext processContainerDmc = procService.createContainerContextFromGroupId(fControlDmc, MIProcesses.UNIQUE_GROUP_ID);
fCommandControl.getSession().dispatchEvent(
new ContainerExitedDMEvent(processContainerDmc), fCommandControl.getProperties());
}
}
public void commandQueued(ICommandToken token) { public void commandQueued(ICommandToken token) {
// Do nothing. // Do nothing.
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Ericsson and others. * Copyright (c) 2009, 2011 Ericsson and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -11,21 +11,21 @@
package org.eclipse.cdt.dsf.mi.service.command.commands; package org.eclipse.cdt.dsf.mi.service.command.commands;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
/** /**
* -inferior-tty-set TTY * -inferior-tty-set TTY
* *
* Set terminal for future runs of the program being debugged. * Set terminal for future runs of the specified program.
*/ */
public class MIInferiorTTYSet extends MICommand<MIInfo> public class MIInferiorTTYSet extends MICommand<MIInfo>
{ {
/** /**
* @since 1.1 * @since 4.0
*/ */
public MIInferiorTTYSet(ICommandControlDMContext dmc, String tty) { public MIInferiorTTYSet(IMIContainerDMContext dmc, String tty) {
super(dmc, "-inferior-tty-set", null, new String[] {tty}); //$NON-NLS-1$ super(dmc, "-inferior-tty-set", null, new String[] {tty}); //$NON-NLS-1$
} }
} }