diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java index aad1cdbce91..cf1f9557cb0 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java @@ -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 fProcessNames = new HashMap(); + // 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 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(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 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(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); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java index de59216d162..bcffcdb9ae0 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java @@ -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(getExecutor(), rm) { - @Override - protected void handleSuccess() { - fCommandControl.getInferiorProcess().setPid(null); - rm.done(); - } - }); + new DataRequestMonitor(getExecutor(), rm)); } else { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$ rm.done(); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java index e082f32510f..98f974db453 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java @@ -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(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); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java index dace4e14e23..88ef27ae7b1 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java @@ -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(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); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java index 93cfc61f5e7..e8bc851c3f7 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java @@ -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(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(); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java index 0733d644a24..d72f49c322a 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java @@ -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 fFeatures = new ArrayList(); /** @@ -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(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(); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java index 4fbbb74bb8f..fb7ef002ba5 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java @@ -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 diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIProcesses.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIProcesses.java index fcf60e784cc..a6b45e760c4 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIProcesses.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIProcesses.java @@ -496,8 +496,7 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses, ICa new DataRequestMonitor(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); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java index 9e7aa7c40dd..4819b3bc3b3 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java @@ -629,7 +629,8 @@ public class CommandFactory { return new MIGDBShowExitCode(ctx); } - public ICommand createMIInferiorTTYSet(ICommandControlDMContext dmc, String tty) { + /** @since 4.0 */ + public ICommand createMIInferiorTTYSet(IMIContainerDMContext dmc, String tty) { return new MIInferiorTTYSet(dmc, tty); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIInferiorProcess.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIInferiorProcess.java index 11acf7f4dd2..c3febf3a6e2 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIInferiorProcess.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIInferiorProcess.java @@ -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(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(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(); + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIRunControlEventProcessor.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIRunControlEventProcessor.java index 3e6811e6be7..afbd3ce5138 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIRunControlEventProcessor.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIRunControlEventProcessor.java @@ -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. } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIInferiorTTYSet.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIInferiorTTYSet.java index 9ea0acbeb66..a7b816f2676 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIInferiorTTYSet.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIInferiorTTYSet.java @@ -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 { /** - * @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$ } } \ No newline at end of file