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;
|
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,12 +190,8 @@ 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) {
|
name = fBackend.getProgramPath().lastSegment();
|
||||||
String inferiorPidStr = inferior.getPid();
|
|
||||||
if (inferiorPidStr != null && Integer.parseInt(inferiorPidStr) == pid) {
|
|
||||||
name = fBackend.getProgramPath().lastSegment();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
|
@ -187,8 +200,9 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
|
||||||
// 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);
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -799,13 +811,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
public void execute(RequestMonitor rm) {
|
public void execute(RequestMonitor rm) {
|
||||||
// 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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -308,8 +351,6 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
@ -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.
|
* 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
|
||||||
|
@ -283,10 +238,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
|
||||||
public AbstractCLIProcess getCLIProcess() {
|
public AbstractCLIProcess getCLIProcess() {
|
||||||
return fCLIProcess;
|
return fCLIProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MIInferiorProcess getInferiorProcess() {
|
|
||||||
return fInferiorProcess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
|
@ -437,9 +388,8 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
|
||||||
requestMonitor.done();
|
requestMonitor.done();
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -467,8 +412,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
|
||||||
requestMonitor.done();
|
requestMonitor.done();
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,32 +19,30 @@ 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,
|
||||||
* to complete the initialization. It will perform the final steps
|
* to complete the initialization. It will perform the final steps
|
||||||
* 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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
fContainerDMContext = container;
|
||||||
|
|
||||||
|
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSession.getId());
|
||||||
|
fCommandControl = tracker.getService(IMICommandControl.class);
|
||||||
|
tracker.dispose();
|
||||||
|
|
||||||
|
fCommandFactory = fCommandControl.getCommandFactory();
|
||||||
|
|
||||||
if (fCommandControl instanceof IMICommandControl) {
|
fCommandControl.addEventListener(this);
|
||||||
fCommandFactory = ((IMICommandControl)fCommandControl).getCommandFactory();
|
fCommandControl.addCommandListener(this);
|
||||||
} else {
|
|
||||||
// Should not happen
|
|
||||||
fCommandFactory = new CommandFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
commandControl.addEventListener(this);
|
if (pty != null) {
|
||||||
commandControl.addCommandListener(this);
|
fOutputStream = pty.getOutputStream();
|
||||||
|
fInputStream = pty.getInputStream();
|
||||||
fPty = p;
|
|
||||||
if (fPty != null) {
|
|
||||||
fOutputStream = fPty.getOutputStream();
|
|
||||||
fInputStream = fPty.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")
|
|
||||||
public IExecutionDMContext getExecutionContext() {
|
|
||||||
return fContainerDMContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 1.1
|
|
||||||
*/
|
|
||||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
|
||||||
public void setContainerContext(IContainerDMContext containerDmc) {
|
|
||||||
fContainerDMContext = containerDmc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfinedToDsfExecutor("fSession#getExecutor")
|
@ConfinedToDsfExecutor("fSession#getExecutor")
|
||||||
synchronized void setState(State state) {
|
private synchronized void setTerminated() {
|
||||||
if (fState == State.TERMINATED) return;
|
if (fTerminated) return;
|
||||||
fState = state;
|
fTerminated = true;
|
||||||
if (fState == State.TERMINATED) {
|
closeIO();
|
||||||
closeIO();
|
|
||||||
}
|
|
||||||
notifyAll();
|
notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,69 +366,10 @@ public class MIInferiorProcess extends Process
|
||||||
public OutputStream getPipedErrorStream() {
|
public OutputStream getPipedErrorStream() {
|
||||||
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
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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$
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue