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:
parent
0e149f27ae
commit
bcb875257f
12 changed files with 251 additions and 416 deletions
|
@ -10,6 +10,7 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
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.service.DsfServiceEventHandler;
|
||||
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.IPath;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
|
@ -88,6 +90,12 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
|||
// processes that are running
|
||||
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) {
|
||||
super(session);
|
||||
}
|
||||
|
@ -150,6 +158,18 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
|||
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
|
||||
public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm) {
|
||||
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
|
||||
// of processes to attach to, and in this case, we do have the proper pid.
|
||||
if (pidStr == null || pidStr.length() == 0) {
|
||||
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
|
||||
if (inferiorProcess != null) {
|
||||
pidStr = inferiorProcess.getPid();
|
||||
}
|
||||
pidStr = fProcId;
|
||||
}
|
||||
int pid = -1;
|
||||
try {
|
||||
|
@ -173,12 +190,8 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
|||
String name = fProcessNames.get(pid);
|
||||
if (name == null) {
|
||||
// Hm. Strange. But if the pid is our inferior's, we can just use the binary name
|
||||
MIInferiorProcess inferior = fGdb.getInferiorProcess();
|
||||
if (inferior != null) {
|
||||
String inferiorPidStr = inferior.getPid();
|
||||
if (inferiorPidStr != null && Integer.parseInt(inferiorPidStr) == pid) {
|
||||
name = fBackend.getProgramPath().lastSegment();
|
||||
}
|
||||
if (fProcId != null && Integer.parseInt(fProcId) == pid) {
|
||||
name = fBackend.getProgramPath().lastSegment();
|
||||
}
|
||||
}
|
||||
if (name == null) {
|
||||
|
@ -187,8 +200,9 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
|||
// to keep GDB running has been selected.
|
||||
name = "Unknown name"; //$NON-NLS-1$
|
||||
|
||||
// Until bug 305385 is fixed, the above code will not work, so we assume we
|
||||
// are looking for our own process
|
||||
// Until bug 305385 is fixed, the above code will not work, because
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -225,12 +239,8 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
|||
new DataRequestMonitor<IDMContext>(ImmediateExecutor.getInstance(), rm) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
|
||||
if (inferiorProcess != null) {
|
||||
inferiorProcess.setContainerContext(containerDmc);
|
||||
inferiorProcess.setPid(((IMIProcessDMContext)procCtx).getProcId());
|
||||
}
|
||||
|
||||
// For an attach, we actually know the pid, so let's remember it
|
||||
fProcId = ((IMIProcessDMContext)procCtx).getProcId();
|
||||
IDMContext containerDmc = getData();
|
||||
rm.setData(containerDmc);
|
||||
|
||||
|
@ -274,11 +284,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
|||
new RequestMonitor(getExecutor(), rm) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
|
||||
if (inferiorProcess != null) {
|
||||
inferiorProcess.setPid(null);
|
||||
}
|
||||
|
||||
fProcId = null;
|
||||
rm.done();
|
||||
}
|
||||
});
|
||||
|
@ -303,11 +309,7 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
|||
|
||||
@Override
|
||||
public void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm) {
|
||||
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
|
||||
if (fConnected &&
|
||||
inferiorProcess != null &&
|
||||
inferiorProcess.getState() != MIInferiorProcess.State.TERMINATED) {
|
||||
|
||||
if (fConnected) {
|
||||
super.getProcessesBeingDebugged(dmc, rm);
|
||||
} else {
|
||||
rm.setData(new IDMContext[0]);
|
||||
|
@ -441,16 +443,57 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
|||
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
|
||||
*/
|
||||
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
|
||||
protected void handleSuccess() {
|
||||
fGdb.createInferiorProcess();
|
||||
final MIInferiorProcess inferior = fGdb.getInferiorProcess();
|
||||
inferior.setContainerContext(containerDmc);
|
||||
Process inferiorProcess;
|
||||
if (fPty == null) {
|
||||
inferiorProcess = new MIInferiorProcess(containerDmc, fBackend.getMIOutputStream());
|
||||
} else {
|
||||
inferiorProcess = new MIInferiorProcess(containerDmc, fPty);
|
||||
}
|
||||
|
||||
final Process inferior = inferiorProcess;
|
||||
|
||||
final String label = fBackend.getProgramPath().lastSegment();
|
||||
final ILaunch launch = (ILaunch)getSession().getModelAdapter(ILaunch.class);
|
||||
|
|
|
@ -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.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.events.MIThreadGroupCreatedEvent;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadGroupExitedEvent;
|
||||
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
|
||||
// This works when we run a single process
|
||||
// but will break for multi-process!!!
|
||||
// khouzam
|
||||
if (getThreadToGroupMap().isEmpty()) {
|
||||
groupId = MIProcesses.UNIQUE_GROUP_ID;
|
||||
} else {
|
||||
|
@ -618,6 +618,18 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
|||
|
||||
/** @since 4.0 */
|
||||
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);
|
||||
if (pid == null) {
|
||||
pid = groupId;
|
||||
|
@ -799,13 +811,7 @@ 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()));
|
||||
|
||||
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);
|
||||
|
||||
|
@ -873,13 +879,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
|||
|
||||
fCommandControl.queueCommand(
|
||||
fCommandFactory.createMITargetDetach(controlDmc, procDmc.getProcId()),
|
||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
fCommandControl.getInferiorProcess().setPid(null);
|
||||
rm.done();
|
||||
}
|
||||
});
|
||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
|
||||
} else {
|
||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$
|
||||
rm.done();
|
||||
|
|
|
@ -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.IRunControl2;
|
||||
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.IMIExecutionDMContext;
|
||||
import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext;
|
||||
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
|
||||
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
|
||||
import org.eclipse.cdt.dsf.mi.service.MIRunControl;
|
||||
|
@ -77,7 +77,6 @@ public class GDBRunControl extends MIRunControl {
|
|||
|
||||
private IGDBBackend fGdb;
|
||||
private IMIProcesses fProcService;
|
||||
private IGDBControl fGbControlService;
|
||||
private CommandFactory fCommandFactory;
|
||||
|
||||
// Record list of execution contexts
|
||||
|
@ -104,7 +103,6 @@ public class GDBRunControl extends MIRunControl {
|
|||
|
||||
fGdb = getServicesTracker().getService(IGDBBackend.class);
|
||||
fProcService = getServicesTracker().getService(IMIProcesses.class);
|
||||
fGbControlService = getServicesTracker().getService(IGDBControl.class);
|
||||
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
|
||||
|
||||
register(new String[]{IRunControl.class.getName(),
|
||||
|
@ -135,7 +133,7 @@ public class GDBRunControl extends MIRunControl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void suspend(IExecutionDMContext context, final RequestMonitor rm){
|
||||
public void suspend(final IExecutionDMContext context, final RequestMonitor rm){
|
||||
canSuspend(
|
||||
context,
|
||||
new DataRequestMonitor<Boolean>(getExecutor(), rm) {
|
||||
|
@ -151,7 +149,8 @@ public class GDBRunControl extends MIRunControl {
|
|||
if (fGdb.getIsAttachSession()
|
||||
&& fGdb.getSessionType() != SessionType.REMOTE
|
||||
&& 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) {
|
||||
fGdb.interruptInferiorAndWait(Long.parseLong(inferiorPid), IGDBBackend.INTERRUPT_TIMEOUT_DEFAULT, rm);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
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.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.MIInferiorProcess;
|
||||
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.cdt.utils.pty.PTY;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.debug.core.DebugPlugin;
|
||||
|
@ -60,6 +61,7 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
|
|||
private CommandFactory fCommandFactory;
|
||||
private IGDBProcesses fProcService;
|
||||
private IReverseRunControl fReverseService;
|
||||
private IGDBBackend fBackend;
|
||||
|
||||
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
|
||||
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
|
||||
// Although we can access this through Sequence.getRequestMonitor(), we would loose the type-checking.
|
||||
// Therefore, doing it like this is more future-proof.
|
||||
|
@ -144,6 +148,7 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
|
|||
"stepInitializeBaseSequence", //$NON-NLS-1$
|
||||
"stepInsertStopOnMainBreakpoint", //$NON-NLS-1$
|
||||
"stepSetBreakpointForReverse", //$NON-NLS-1$
|
||||
"stepInitializeInputOutput", //$NON-NLS-1$
|
||||
"stepCreateConsole", //$NON-NLS-1$
|
||||
"stepRunProgram", //$NON-NLS-1$
|
||||
"stepSetReverseOff", //$NON-NLS-1$
|
||||
|
@ -166,6 +171,7 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
|
|||
fCommandControl = fTracker.getService(IGDBControl.class);
|
||||
fCommandFactory = fTracker.getService(IMICommandControl.class).getCommandFactory();
|
||||
fProcService = fTracker.getService(IGDBProcesses.class);
|
||||
fBackend = fTracker.getService(IGDBBackend.class);
|
||||
|
||||
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$
|
||||
|
@ -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.
|
||||
*/
|
||||
@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();
|
||||
Process inferiorProcess;
|
||||
if (fPty == null) {
|
||||
inferiorProcess = new MIInferiorProcess(fContainerDmc, fBackend.getMIOutputStream());
|
||||
} else {
|
||||
inferiorProcess = new MIInferiorProcess(fContainerDmc, fPty);
|
||||
}
|
||||
|
||||
final Process inferior = inferiorProcess;
|
||||
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();
|
||||
|
@ -308,8 +351,6 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
|
|||
rm.done();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -329,13 +370,8 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
|
|||
// Now that the process is started, the pid has been allocated
|
||||
// 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.
|
||||
|
||||
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);
|
||||
|
|
|
@ -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.launching.FinalLaunchSequence;
|
||||
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;
|
||||
|
@ -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.CommandFactory;
|
||||
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.output.MIInfo;
|
||||
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.CoreException;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
|
@ -101,9 +98,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
|
|||
private MIRunControlEventProcessor fMIEventProcessor;
|
||||
private CLIEventProcessor fCLICommandProcessor;
|
||||
private AbstractCLIProcess fCLIProcess;
|
||||
private MIInferiorProcess fInferiorProcess;
|
||||
|
||||
private PTY fPty;
|
||||
|
||||
/**
|
||||
* @since 3.0
|
||||
|
@ -225,51 +219,12 @@ 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.
|
||||
*/
|
||||
public void createInferiorProcess() {
|
||||
if (fPty == null) {
|
||||
fInferiorProcess = new MIInferiorProcess(GDBControl.this, fMIBackend.getMIOutputStream());
|
||||
} else {
|
||||
fInferiorProcess = new MIInferiorProcess(GDBControl.this, fPty);
|
||||
}
|
||||
private void createInferiorProcess() {
|
||||
// khouzam BROKEN because no one does the below when we restart
|
||||
|
||||
// Create the CLI event processor each time this method is called
|
||||
// to reset the internal thread id count
|
||||
|
@ -283,10 +238,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
|
|||
public AbstractCLIProcess getCLIProcess() {
|
||||
return fCLIProcess;
|
||||
}
|
||||
|
||||
public MIInferiorProcess getInferiorProcess() {
|
||||
return fInferiorProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
|
@ -437,9 +388,8 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
|
|||
requestMonitor.done();
|
||||
return;
|
||||
}
|
||||
|
||||
createInferiorProcess();
|
||||
|
||||
fCLICommandProcessor = new CLIEventProcessor(GDBControl.this, fControlDmc);
|
||||
fMIEventProcessor = new MIRunControlEventProcessor(GDBControl.this, fControlDmc);
|
||||
|
||||
requestMonitor.done();
|
||||
|
@ -450,7 +400,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
|
|||
fCLICommandProcessor.dispose();
|
||||
fMIEventProcessor.dispose();
|
||||
fCLIProcess.dispose();
|
||||
fInferiorProcess.dispose();
|
||||
|
||||
requestMonitor.done();
|
||||
}
|
||||
|
|
|
@ -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.service.IGDBBackend;
|
||||
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.BackendStateChangedEvent;
|
||||
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.CommandFactory;
|
||||
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.output.MIInfo;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIListFeaturesInfo;
|
||||
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.CoreException;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
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 CLIEventProcessor_7_0 fCLICommandProcessor;
|
||||
private AbstractCLIProcess fCLIProcess;
|
||||
private MIInferiorProcess fInferiorProcess = null;
|
||||
|
||||
private PTY fPty;
|
||||
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() {
|
||||
return fCLIProcess;
|
||||
}
|
||||
|
||||
public MIInferiorProcess getInferiorProcess() {
|
||||
return fInferiorProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
|
@ -467,8 +412,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
|
|||
requestMonitor.done();
|
||||
return;
|
||||
}
|
||||
|
||||
createInferiorProcess();
|
||||
|
||||
fCLICommandProcessor = new CLIEventProcessor_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();
|
||||
fMIEventProcessor.dispose();
|
||||
fCLIProcess.dispose();
|
||||
fInferiorProcess.dispose();
|
||||
|
||||
requestMonitor.done();
|
||||
}
|
||||
|
|
|
@ -19,32 +19,30 @@ import java.util.Properties;
|
|||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
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.MIInferiorProcess;
|
||||
|
||||
public interface IGDBControl extends IMICommandControl {
|
||||
|
||||
void terminate(final RequestMonitor rm);
|
||||
void initInferiorInputOutput(final RequestMonitor requestMonitor);
|
||||
|
||||
void createInferiorProcess();
|
||||
|
||||
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,
|
||||
* to complete the initialization. It will perform the final steps
|
||||
* to configure GDB for the type of debugging session chosen by the
|
||||
* user.
|
||||
*
|
||||
* @param requestMonitor The requestMonitor indicating that the
|
||||
* final steps if initialization are completed.
|
||||
* @param rm The requestMonitor indicating that the final steps if
|
||||
* initialization are completed.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
void completeInitialization(RequestMonitor requestMonitor);
|
||||
void completeInitialization(RequestMonitor rm);
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
|
|
|
@ -496,8 +496,7 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses, ICa
|
|||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
IMIContainerDMContext containerDmc = createContainerContext(procCtx,
|
||||
((IMIProcessDMContext)procCtx).getProcId());
|
||||
IMIContainerDMContext containerDmc = createContainerContext(procCtx, MIProcesses.UNIQUE_GROUP_ID);
|
||||
getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc),
|
||||
getProperties());
|
||||
rm.setData(containerDmc);
|
||||
|
|
|
@ -629,7 +629,8 @@ public class CommandFactory {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.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.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.ICommandResult;
|
||||
import org.eclipse.cdt.dsf.debug.service.command.ICommandToken;
|
||||
import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
||||
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.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.MIInfo;
|
||||
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.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;
|
||||
|
@ -75,7 +68,7 @@ public class MIInferiorProcess extends Process
|
|||
implements IEventListener, ICommandListener
|
||||
{
|
||||
|
||||
public enum State { RUNNING, STOPPED, TERMINATED }
|
||||
private boolean fTerminated;
|
||||
|
||||
private final OutputStream fOutputStream;
|
||||
private final InputStream fInputStream;
|
||||
|
@ -86,9 +79,8 @@ public class MIInferiorProcess extends Process
|
|||
private final PipedOutputStream fErrorStreamPiped;
|
||||
|
||||
private final DsfSession fSession;
|
||||
private final PTY fPty;
|
||||
|
||||
private final ICommandControlService fCommandControl;
|
||||
private final IMICommandControl fCommandControl;
|
||||
private CommandFactory fCommandFactory;
|
||||
|
||||
private IContainerDMContext fContainerDMContext;
|
||||
|
@ -110,75 +102,59 @@ public class MIInferiorProcess extends Process
|
|||
*/
|
||||
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
|
||||
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
|
||||
* 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.
|
||||
* @since 1.1
|
||||
* @since 4.0
|
||||
*/
|
||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
||||
public MIInferiorProcess(ICommandControlService commandControl, OutputStream gdbOutputStream) {
|
||||
this(commandControl, gdbOutputStream, null);
|
||||
public MIInferiorProcess(IContainerDMContext container, OutputStream gdbOutputStream) {
|
||||
this(container, gdbOutputStream, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an inferior process object which uses the given terminal
|
||||
* 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.
|
||||
* @since 1.1
|
||||
* @since 4.0
|
||||
*/
|
||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
||||
public MIInferiorProcess(ICommandControlService commandControl, PTY p) {
|
||||
this(commandControl, null, p);
|
||||
public MIInferiorProcess(IContainerDMContext container, PTY p) {
|
||||
this(container, null, p);
|
||||
}
|
||||
|
||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
||||
private MIInferiorProcess(ICommandControlService commandControl, final OutputStream gdbOutputStream, PTY p) {
|
||||
fCommandControl = commandControl;
|
||||
fSession = commandControl.getSession();
|
||||
private MIInferiorProcess(IContainerDMContext container, final OutputStream gdbOutputStream, PTY pty) {
|
||||
fSession = DsfSession.getSession(container.getSessionId());
|
||||
fSession.addServiceEventListener(this, null);
|
||||
|
||||
fContainerDMContext = container;
|
||||
|
||||
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSession.getId());
|
||||
fCommandControl = tracker.getService(IMICommandControl.class);
|
||||
tracker.dispose();
|
||||
|
||||
fCommandFactory = fCommandControl.getCommandFactory();
|
||||
|
||||
if (fCommandControl instanceof IMICommandControl) {
|
||||
fCommandFactory = ((IMICommandControl)fCommandControl).getCommandFactory();
|
||||
} else {
|
||||
// Should not happen
|
||||
fCommandFactory = new CommandFactory();
|
||||
}
|
||||
fCommandControl.addEventListener(this);
|
||||
fCommandControl.addCommandListener(this);
|
||||
|
||||
commandControl.addEventListener(this);
|
||||
commandControl.addCommandListener(this);
|
||||
|
||||
fPty = p;
|
||||
if (fPty != null) {
|
||||
fOutputStream = fPty.getOutputStream();
|
||||
fInputStream = fPty.getInputStream();
|
||||
if (pty != null) {
|
||||
fOutputStream = pty.getOutputStream();
|
||||
fInputStream = pty.getInputStream();
|
||||
fInputStreamPiped = null;
|
||||
} else {
|
||||
fOutputStream = new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (getState() != State.RUNNING) {
|
||||
throw new IOException("Target is not running"); //$NON-NLS-1$
|
||||
}
|
||||
gdbOutputStream.write(b);
|
||||
}
|
||||
};
|
||||
|
@ -215,22 +191,11 @@ public class MIInferiorProcess extends Process
|
|||
|
||||
closeIO();
|
||||
|
||||
setState(State.TERMINATED);
|
||||
setTerminated();
|
||||
|
||||
fDisposed = true;
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
protected DsfSession getSession() {
|
||||
return fSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1
|
||||
*/
|
||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
||||
protected ICommandControlService getCommandControlService() { return fCommandControl; }
|
||||
|
||||
|
||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
||||
protected boolean isDisposed() { return fDisposed; }
|
||||
|
||||
|
@ -251,9 +216,9 @@ public class MIInferiorProcess extends Process
|
|||
|
||||
@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
|
||||
public synchronized void waitForSync() throws InterruptedException {
|
||||
assert !getSession().getExecutor().isInExecutorThread();
|
||||
assert !fSession.getExecutor().isInExecutorThread();
|
||||
|
||||
while (getState() != State.TERMINATED) {
|
||||
while (!fTerminated) {
|
||||
wait(100);
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +229,7 @@ public class MIInferiorProcess extends Process
|
|||
@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
|
||||
@Override
|
||||
public int waitFor() throws InterruptedException {
|
||||
assert !getSession().getExecutor().isInExecutorThread();
|
||||
assert !fSession.getExecutor().isInExecutorThread();
|
||||
|
||||
waitForSync();
|
||||
return exitValue();
|
||||
|
@ -273,7 +238,7 @@ public class MIInferiorProcess extends Process
|
|||
@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
|
||||
@Override
|
||||
public int exitValue() {
|
||||
assert !getSession().getExecutor().isInExecutorThread();
|
||||
assert !fSession.getExecutor().isInExecutorThread();
|
||||
|
||||
synchronized (this) {
|
||||
if (fExitCode != null) {
|
||||
|
@ -295,14 +260,16 @@ public class MIInferiorProcess extends Process
|
|||
if (isDisposed()) {
|
||||
rm.setData(0);
|
||||
rm.done();
|
||||
} else if (getState() != State.TERMINATED) {
|
||||
} else if (!fTerminated) {
|
||||
// This will cause ExecutionException to be thrown with a CoreException,
|
||||
// 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.done();
|
||||
} else {
|
||||
getCommandControlService().queueCommand(
|
||||
fCommandFactory.createMIGDBShowExitCode(getCommandControlService().getContext()),
|
||||
// The exitCode from GDB does not seem to be handled for multi-process
|
||||
// so there is no point is specifying the container
|
||||
fCommandControl.queueCommand(
|
||||
fCommandFactory.createMIGDBShowExitCode(fCommandControl.getContext()),
|
||||
new DataRequestMonitor<MIGDBShowExitCodeInfo>(fSession.getExecutor(), rm) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
|
@ -371,7 +338,7 @@ public class MIInferiorProcess extends Process
|
|||
|
||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
||||
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());
|
||||
IProcesses procService = tracker.getService(IProcesses.class);
|
||||
|
@ -380,35 +347,15 @@ public class MIInferiorProcess extends Process
|
|||
IProcessDMContext procDmc = DMContexts.getAncestorOfType(fContainerDMContext, IProcessDMContext.class);
|
||||
procService.terminate(procDmc, new RequestMonitor(ImmediateExecutor.getInstance(), null));
|
||||
} else {
|
||||
setState(State.TERMINATED);
|
||||
setTerminated();
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public synchronized State getState() {
|
||||
return fState;
|
||||
}
|
||||
|
||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
||||
public IExecutionDMContext getExecutionContext() {
|
||||
return fContainerDMContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
private synchronized void setTerminated() {
|
||||
if (fTerminated) return;
|
||||
fTerminated = true;
|
||||
closeIO();
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
|
@ -419,69 +366,10 @@ public class MIInferiorProcess extends Process
|
|||
public OutputStream getPipedErrorStream() {
|
||||
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) {
|
||||
for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) {
|
||||
if (oobr instanceof MIExecAsyncOutput) {
|
||||
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 (oobr instanceof MITargetStreamOutput) {
|
||||
if (fSuppressTargetOutputCounter > 0) return;
|
||||
MITargetStreamOutput tgtOut = (MITargetStreamOutput)oobr;
|
||||
if (fInputStreamPiped != null && tgtOut.getString() != null) {
|
||||
|
@ -513,26 +401,6 @@ public class MIInferiorProcess extends Process
|
|||
if (token.getCommand() instanceof CLICommand<?>) {
|
||||
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
|
||||
public void eventDispatched(IExitedDMEvent e) {
|
||||
if (e.getDMContext() instanceof IContainerDMContext) {
|
||||
setState(State.TERMINATED);
|
||||
if (e.getDMContext() instanceof IMIContainerDMContext) {
|
||||
// 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.
|
||||
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=305385#c20
|
||||
//
|
||||
// /**
|
||||
// * @since 3.0
|
||||
// */
|
||||
// @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
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
/**
|
||||
* @since 4.0
|
||||
*/
|
||||
@DsfServiceEventHandler
|
||||
public void eventDispatched(ICommandControlShutdownDMEvent e) {
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.mi.service.IMIProcesses;
|
||||
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.command.commands.CLICommand;
|
||||
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());
|
||||
} else if ("exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
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$
|
||||
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)) {
|
||||
event = MIStoppedEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
|
||||
}
|
||||
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) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -11,21 +11,21 @@
|
|||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* -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>
|
||||
{
|
||||
/**
|
||||
* @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$
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue