From d18ba1931354aa1304b32efafeb1b0b535fd7767 Mon Sep 17 00:00:00 2001
From: Pawel Piech
Date: Tue, 14 Oct 2008 17:31:52 +0000
Subject: [PATCH] [240092] - [launch] The way to launch & configure GDB process
in DSF is not customizable
---
.../launch/PDAVirtualMachineVMNode.java | 2 +-
.../dd/examples/pda/launch/PDALaunch.java | 4 +-
.../pda/launch/PDALaunchDelegate.java | 129 ++--
.../pda/launch/PDAServicesInitSequence.java | 25 +-
.../dd/examples/pda/service/PDABackend.java | 320 ++++++++++
.../examples/pda/service/PDABreakpoints.java | 14 +-
.../pda/service/PDACommandControl.java | 109 ++--
.../examples/pda/service/PDAExpressions.java | 6 +
.../dd/examples/pda/service/PDARegisters.java | 2 +-
.../examples/pda/service/PDARunControl.java | 2 +-
.../service/PDAVirtualMachineDMContext.java | 7 +-
.../tests/pda/service/command/BasicTests.java | 2 +-
.../command/CommandControlTestsBase.java | 43 +-
.../eclipse/dd/tests/pda/util/Launching.java | 101 ++--
.../ui/actions/DsfTerminateCommand.java | 11 +-
.../launching/FinalLaunchSequence.java | 98 ++-
.../launching/GdbLaunchDelegate.java | 3 +-
.../launching/ServicesLaunchSequence.java | 10 +
.../launching/ShutdownSequence.java | 6 +
.../provisional/service/GDBBackend.java | 556 ++++++++++++++++++
.../provisional/service/GDBRunControl.java | 6 +-
.../service/GDBRunControl_7_0.java | 6 +-
.../service/GdbDebugServicesFactory.java | 16 +-
.../provisional/service/IGDBBackend.java | 96 +++
.../service/command/GDBCLIProcess.java | 102 ----
.../service/command/GDBControl.java | 312 ++--------
.../service/command/GDBControl_7_0.java | 304 ++--------
.../service/command/GDBInferiorProcess.java | 10 +-
.../service/command/IGDBControl.java | 11 -
.../org/eclipse/dd/mi/service/IMIBackend.java | 91 +++
.../mi/service/command/AbstractMIControl.java | 14 +-
.../service/command/MIBackendCLIProcess.java | 173 ++++++
.../service/command/commands/MIBreakList.java | 2 +-
.../command/output/MIBreakListInfo.java | 2 +-
34 files changed, 1584 insertions(+), 1011 deletions(-)
create mode 100644 plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABackend.java
create mode 100644 plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBBackend.java
create mode 100644 plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/IGDBBackend.java
delete mode 100644 plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBCLIProcess.java
create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIBackend.java
create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIBackendCLIProcess.java
diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java
index 0ab91f2b14b..c6c7cb4efac 100644
--- a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java
+++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java
@@ -66,7 +66,7 @@ public class PDAVirtualMachineVMNode extends AbstractContainerVMNode
return;
}
- update.setChild(createVMContext(commandControl.getVirtualMachineDMContext()), 0);
+ update.setChild(createVMContext(commandControl.getContext()), 0);
update.done();
}
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDALaunch.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDALaunch.java
index 5db49e184bc..2d8e66d9734 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDALaunch.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDALaunch.java
@@ -88,7 +88,7 @@ implements ITerminate
* synchronization issues.
*/
@ConfinedToDsfExecutor("getSession().getExecutor()")
- public void initializeServices(String program, int requestPort, int eventPort, final RequestMonitor rm)
+ public void initializeServices(String program, final RequestMonitor rm)
{
// Double-check that we're being called in the correct thread.
assert fExecutor.isInExecutorThread();
@@ -110,7 +110,7 @@ implements ITerminate
// canceled if shutdownServices() is called before the sequence
// completes.
fInitializationSequence = new PDAServicesInitSequence(
- getSession(), program, requestPort, eventPort,
+ getSession(), this, program,
new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleCompleted() {
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDALaunchDelegate.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDALaunchDelegate.java
index 96069ee9d51..5b8393125fb 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDALaunchDelegate.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDALaunchDelegate.java
@@ -12,24 +12,18 @@
*******************************************************************************/
package org.eclipse.dd.examples.pda.launch;
-import java.io.File;
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.ExecutionException;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.dd.dsf.concurrent.Query;
+import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.examples.pda.PDAPlugin;
+import org.eclipse.dd.examples.pda.service.PDABackend;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
@@ -92,79 +86,22 @@ public class PDALaunchDelegate extends LaunchConfigurationDelegate {
abort("Perl program unspecified.", null);
}
- int requestPort = findFreePort();
- int eventPort = findFreePort();
- if (requestPort == -1 || eventPort == -1) {
- abort("Unable to find free port", null);
- }
-
- launchProcess(launch, program, requestPort, eventPort);
PDALaunch pdaLaunch = (PDALaunch)launch;
- initServices(pdaLaunch, program, requestPort, eventPort);
+ initServices(pdaLaunch, program);
+ createProcess(pdaLaunch);
}
-
- /**
- * Launches PDA interpreter with the given program.
- *
- * @param launch Launch that will contain the new process.
- * @param program PDA program to use in the interpreter.
- * @param requestPort The port number for connecting the request socket.
- * @param eventPort The port number for connecting the events socket.
- *
- * @throws CoreException
- */
- private void launchProcess(ILaunch launch, String program, int requestPort, int eventPort) throws CoreException {
- List commandList = new ArrayList();
-
- // Get Java VM path
- String javaVMHome = System.getProperty("java.home");
- String javaVMExec = javaVMHome + File.separatorChar + "bin" + File.separatorChar + "java";
- if (File.separatorChar == '\\') {
- javaVMExec += ".exe";
- }
- File exe = new File(javaVMExec);
- if (!exe.exists()) {
- abort(MessageFormat.format("Specified java VM executable {0} does not exist.", new Object[]{javaVMExec}), null);
- }
- commandList.add(javaVMExec);
-
- commandList.add("-cp");
- commandList.add(File.pathSeparator + PDAPlugin.getFileInPlugin(new Path("bin")));
-
- commandList.add("org.eclipse.dd.examples.pdavm.PDAVirtualMachine");
-
- // Add PDA program
- IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(program));
- if (!file.exists()) {
- abort(MessageFormat.format("PDA program {0} does not exist.", new Object[] {file.getFullPath().toString()}), null);
- }
-
- commandList.add(file.getLocation().toOSString());
-
- // Add debug arguments - i.e. '-debug requestPort eventPort'
- commandList.add("-debug");
- commandList.add("" + requestPort);
- commandList.add("" + eventPort);
-
- // Launch the perl process.
- String[] commandLine = commandList.toArray(new String[commandList.size()]);
- Process process = DebugPlugin.exec(commandLine, null);
-
- // Create a debug platform process object and add it to the launch.
- DebugPlugin.newProcess(launch, process, javaVMHome);
- }
-
+
/**
* Calls the launch to initialize DSF services for this launch.
*/
- private void initServices(final PDALaunch pdaLaunch, final String program, final int requestPort, final int eventPort)
+ private void initServices(final PDALaunch pdaLaunch, final String program)
throws CoreException
{
// Synchronization object to use when waiting for the services initialization.
Query
*/
public class PDAVirtualMachineDMContext extends PlatformObject
- implements IContainerDMContext, IBreakpointsTargetDMContext
+ implements ICommandControlDMContext, IContainerDMContext, IBreakpointsTargetDMContext
{
final static IDMContext[] EMPTY_PARENTS_ARRAY = new IDMContext[0];
@@ -67,6 +68,10 @@ public class PDAVirtualMachineDMContext extends PlatformObject
return "pda[" + getSessionId() + "]";
}
+ public String getCommandControlId() {
+ return getProgram();
+ }
+
/**
* @see AbstractDMContext#getAdapter(Class)
*/
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java
index 15e03f1dbd1..944a1366849 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java
@@ -82,7 +82,7 @@ public class BasicTests extends CommandControlTestsBase {
}
});
- final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getVirtualMachineDMContext(), "data 1");
+ final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getContext(), "data 1");
// Test sending the command and checking all listeners were called.
Query sendCommandQuery = new Query() {
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java
index 493781ca85a..941ae0b35a3 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java
@@ -26,6 +26,7 @@ import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.Query;
import org.eclipse.dd.dsf.debug.service.command.IEventListener;
import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.examples.pda.service.PDABackend;
import org.eclipse.dd.examples.pda.service.PDACommandControl;
import org.eclipse.dd.examples.pda.service.commands.PDACommandResult;
import org.eclipse.dd.tests.pda.util.Launching;
@@ -41,7 +42,7 @@ public class CommandControlTestsBase {
protected DsfExecutor fExecutor;
protected DsfSession fSession;
- protected Process fPDAProcess;
+ protected PDABackend fPDABackend;
protected PDACommandControl fCommandControl;
private BlockingQueue fEventsQueue = new LinkedBlockingQueue();
@@ -57,16 +58,20 @@ public class CommandControlTestsBase {
}
};
- int requestPort = Launching.findFreePort();
- int eventPort = Launching.findFreePort();
-
- fPDAProcess = Launching.launchPDA(fProgram, requestPort, eventPort);
- fOutputReader = new BufferedReader(new InputStreamReader(fPDAProcess.getInputStream()));
- Assert.assertEquals("-debug " + requestPort + " " + eventPort, fOutputReader.readLine());
-
fExecutor = new DefaultDsfExecutor();
fSession = DsfSession.startSession(fExecutor, "PDA Test");
- fCommandControl = new PDACommandControl(fSession, fProgram, requestPort, eventPort);
+
+ Process proc = Launching.launchPDA(fSession, null, fProgram);
+ Assert.assertNotNull(proc);
+
+ // Remember the backend service of this session.
+ // Note this must be called after the above LaunchPDA().
+ fPDABackend = Launching.getBackendService();
+
+ fOutputReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+ Assert.assertTrue(fOutputReader.readLine().contains("-debug"));
+
+ fCommandControl = new PDACommandControl(fSession);
fCommandControl.addEventListener(new IEventListener() {
public void eventReceived(Object output) {
@@ -82,8 +87,9 @@ public class CommandControlTestsBase {
@After
public void shutdown() throws CoreException, InterruptedException, ExecutionException, IOException {
- fOutputReader.close();
- fPDAProcess.destroy();
+ if (fOutputReader != null) {
+ fOutputReader.close();
+ }
class ShutdownCommandServiceQuery extends Query {
@Override
@@ -97,6 +103,19 @@ public class CommandControlTestsBase {
fExecutor.execute(shutdownQuery);
shutdownQuery.get();
}
+
+ class ShutdownBackendServiceQuery extends Query {
+ @Override
+ protected void execute(DataRequestMonitor rm) {
+ fPDABackend.shutdown(rm);
+ }
+ };
+
+ if (fExecutor != null) {
+ ShutdownBackendServiceQuery shutdownQuery = new ShutdownBackendServiceQuery();
+ fExecutor.execute(shutdownQuery);
+ shutdownQuery.get();
+ }
}
protected void sendCommand(String command) throws Throwable {
@@ -105,7 +124,7 @@ public class CommandControlTestsBase {
protected void sendCommand(String command, String expectedResult) throws Throwable {
- final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getVirtualMachineDMContext(), command);
+ final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getContext(), command);
// Test sending the command and checking all listeners were called.
Query sendCommandQuery = new Query() {
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/util/Launching.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/util/Launching.java
index dfc4f3295d7..7b58ab7c193 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/util/Launching.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/util/Launching.java
@@ -7,85 +7,52 @@
*
* Contributors:
* Wind River Systems - initial API and implementation
+ * Nokia - create and use backend service.
*******************************************************************************/
package org.eclipse.dd.tests.pda.util;
-import java.io.File;
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.List;
-
-import junit.framework.Assert;
+import java.util.concurrent.ExecutionException;
import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.dd.examples.pda.PDAPlugin;
-import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.dd.dsf.concurrent.Query;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.examples.pda.service.PDABackend;
+import org.eclipse.debug.core.Launch;
/**
*
*/
public class Launching {
- public static Process launchPDA(String pdaProgram, int requestPort, int eventPort) throws CoreException {
- Assert.assertTrue("Invalid request port", requestPort > 0);
- Assert.assertTrue("Invalid event port", eventPort > 0);
-
- List commandList = new ArrayList();
-
- // Get Java VM path
- String javaVMHome = System.getProperty("java.home");
- String javaVMExec = javaVMHome + File.separatorChar + "bin" + File.separatorChar + "java";
- File exe = new File(javaVMExec);
- if (!exe.exists()) {
- throw new CoreException(new Status(
- IStatus.ERROR, PDAPlugin.PLUGIN_ID, 0,
- MessageFormat.format("Specified java VM executable {0} does not exist.", new Object[]{javaVMExec}), null));
- }
- commandList.add(javaVMExec);
-
- commandList.add("-cp");
- commandList.add(File.pathSeparator + PDAPlugin.getFileInPlugin(new Path("bin")));
-
- commandList.add("org.eclipse.dd.examples.pdavm.PDAVirtualMachine");
-
- commandList.add(pdaProgram);
+ private static PDABackend fBackendService;
+
+ public static Process launchPDA(DsfSession session, Launch launch, String pdaProgram) throws CoreException {
- // if in debug mode, add debug arguments - i.e. '-debug requestPort eventPort'
-
- commandList.add("-debug");
- commandList.add("" + requestPort);
- commandList.add("" + eventPort);
-
- String[] commandLine = commandList.toArray(new String[commandList.size()]);
-
- return DebugPlugin.exec(commandLine, null);
- }
-
- /**
- * Returns a free port number on localhost, or -1 if unable to find a free port.
- *
- * @return a free port number on localhost, or -1 if unable to find a free port
- */
- public static int findFreePort() {
- ServerSocket socket= null;
- try {
- socket= new ServerSocket(0);
- return socket.getLocalPort();
- } catch (IOException e) {
- } finally {
- if (socket != null) {
- try {
- socket.close();
- } catch (IOException e) {
- }
+ class InitializeBackendServiceQuery extends Query {
+ @Override
+ protected void execute(DataRequestMonitor rm) {
+ fBackendService.initialize(rm);
}
- }
- return -1;
- }
+ };
+ fBackendService = new PDABackend(session, launch, pdaProgram);
+ InitializeBackendServiceQuery initQuery = new InitializeBackendServiceQuery();
+ session.getExecutor().execute(initQuery);
+ try {
+ initQuery.get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ return null;
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ return fBackendService.getProcess();
+ }
+
+ public static PDABackend getBackendService() {
+ return fBackendService;
+ }
}
diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/DsfTerminateCommand.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/DsfTerminateCommand.java
index 7d951f841fa..897c2b4f474 100644
--- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/DsfTerminateCommand.java
+++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/DsfTerminateCommand.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Wind River Systems - initial API and implementation
+ * Nokia - create and use backend service.
*******************************************************************************/
package org.eclipse.dd.gdb.internal.ui.actions;
@@ -19,8 +20,10 @@ import org.eclipse.dd.dsf.debug.ui.actions.DsfCommandRunnable;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.dd.gdb.internal.provisional.service.IGDBBackend;
import org.eclipse.dd.gdb.internal.provisional.service.command.IGDBControl;
import org.eclipse.dd.gdb.internal.ui.GdbUIPlugin;
+import org.eclipse.dd.mi.service.IMIBackend;
import org.eclipse.debug.core.commands.IDebugCommandRequest;
import org.eclipse.debug.core.commands.IEnabledStateRequest;
import org.eclipse.debug.core.commands.ITerminateHandler;
@@ -62,14 +65,14 @@ public class DsfTerminateCommand implements ITerminateHandler {
new DsfRunnable() {
public void run() {
// Get the processes service and the exec context.
- IGDBControl gdbControl = fTracker.getService(IGDBControl.class);
- if (gdbControl == null || dmc == null) {
+ IGDBBackend gdbBackend = fTracker.getService(IGDBBackend.class);
+ if (gdbBackend == null || dmc == null) {
// Context or service already invalid.
request.setEnabled(false);
request.done();
} else {
- // Check the teriminate.
- request.setEnabled(!gdbControl.isGDBExited());
+ // Check the terminate.
+ request.setEnabled(gdbBackend.getState() == IMIBackend.State.STARTED);
request.done();
}
}
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/FinalLaunchSequence.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/FinalLaunchSequence.java
index e21ef32c09b..26947f39481 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/FinalLaunchSequence.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/FinalLaunchSequence.java
@@ -7,27 +7,18 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Nokia - create and use backend service.
*******************************************************************************/
package org.eclipse.dd.gdb.internal.provisional.launching;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
import java.util.List;
-import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
-import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
@@ -39,6 +30,7 @@ import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.gdb.internal.GdbPlugin;
import org.eclipse.dd.gdb.internal.provisional.IGDBLaunchConfigurationConstants;
import org.eclipse.dd.gdb.internal.provisional.actions.IConnect;
+import org.eclipse.dd.gdb.internal.provisional.service.IGDBBackend;
import org.eclipse.dd.gdb.internal.provisional.service.SessionType;
import org.eclipse.dd.gdb.internal.provisional.service.command.IGDBControl;
import org.eclipse.dd.mi.service.CSourceLookup;
@@ -59,9 +51,6 @@ import org.eclipse.dd.mi.service.command.output.MIInfo;
public class FinalLaunchSequence extends Sequence {
Step[] fSteps = new Step[] {
- /*
- * Fetch the control service for later use
- */
new Step() { @Override
public void execute(RequestMonitor requestMonitor) {
fTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fLaunch.getSession().getId());
@@ -73,6 +62,22 @@ public class FinalLaunchSequence extends Sequence {
fTracker = null;
requestMonitor.done();
}},
+
+ /*
+ * Fetch the GDBBackend service for later use
+ */
+ new Step() { @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fGDBBackend = fTracker.getService(IGDBBackend.class);
+ if (fGDBBackend == null) {
+ requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot obtain GDBBackend service", null)); //$NON-NLS-1$
+ }
+
+ requestMonitor.done();
+ }},
+ /*
+ * Fetch the control service for later use
+ */
new Step() { @Override
public void execute(RequestMonitor requestMonitor) {
fCommandControl = fTracker.getService(IGDBControl.class);
@@ -89,8 +94,8 @@ public class FinalLaunchSequence extends Sequence {
new Step() { @Override
public void execute(final RequestMonitor requestMonitor) {
try {
- final String gdbinitFile = fLaunch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT,
- IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT );
+ final String gdbinitFile = fGDBBackend.getGDBInitFile();
+
if (gdbinitFile != null && gdbinitFile.length() > 0) {
fCommandControl.queueCommand(
new CLISource(fCommandControl.getContext(), gdbinitFile),
@@ -134,7 +139,7 @@ public class FinalLaunchSequence extends Sequence {
if (!noFileCommand && execPath != null && !execPath.isEmpty()) {
fCommandControl.queueCommand(
new MIFileExecAndSymbols(fCommandControl.getContext(),
- execPath.toOSString()),
+ execPath.toPortableString()),
new DataRequestMonitor(getExecutor(), requestMonitor));
} else {
requestMonitor.done();
@@ -146,11 +151,9 @@ public class FinalLaunchSequence extends Sequence {
new Step() { @Override
public void execute(final RequestMonitor requestMonitor) {
try {
- String args = fLaunch.getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
- (String)null);
+ String args = fGDBBackend.getProgramArguments();
+
if (args != null) {
- args = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(args);
-
fCommandControl.queueCommand(
new MIGDBSetArgs(fCommandControl.getContext(), args),
new DataRequestMonitor(getExecutor(), requestMonitor));
@@ -167,58 +170,24 @@ public class FinalLaunchSequence extends Sequence {
*/
new Step() {
- private File getWorkingDirectory(RequestMonitor requestMonitor) {
+ private IPath getWorkingDirectory(RequestMonitor requestMonitor) {
IPath path = null;
try {
- String location = fLaunch.getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
- (String)null);
- if (location != null) {
- String expandedLocation = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(location);
- if (expandedLocation.length() > 0) {
- path = new Path(expandedLocation);
- }
- }
-
- if (path == null) {
- // default working dir is the project if this config has a project
- ICProject cp = LaunchUtils.getCProject(fLaunch.getLaunchConfiguration());
- if (cp != null) {
- IProject p = cp.getProject();
- return p.getLocation().toFile();
- }
- } else {
- if (path.isAbsolute()) {
- File dir = new File(path.toOSString());
- if (dir.isDirectory()) {
- return dir;
- }
- } else {
- IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
- if (res instanceof IContainer && res.exists()) {
- return res.getLocation().toFile();
- }
- }
-
- requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1,
- LaunchMessages.getString("AbstractCLaunchDelegate.Working_directory_does_not_exist"), //$NON-NLS-1$
- new FileNotFoundException(LaunchMessages.getFormattedString(
- "AbstractCLaunchDelegate.WORKINGDIRECTORY_PATH_not_found", path.toOSString())))); //$NON-NLS-1$
- requestMonitor.done();
- }
+ path = fGDBBackend.getGDBWorkingDirectory();
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get working directory", e)); //$NON-NLS-1$
requestMonitor.done();
}
- return null;
+ return path;
}
@Override
public void execute(final RequestMonitor requestMonitor) {
- File dir = getWorkingDirectory(requestMonitor);
+ IPath dir = getWorkingDirectory(requestMonitor);
if (dir != null) {
fCommandControl.queueCommand(
- new MIEnvironmentCD(fCommandControl.getContext(), dir.getAbsolutePath()),
+ new MIEnvironmentCD(fCommandControl.getContext(), dir.toPortableString()),
new DataRequestMonitor(getExecutor(), requestMonitor));
} else {
requestMonitor.done();
@@ -314,9 +283,8 @@ public class FinalLaunchSequence extends Sequence {
new Step() { @Override
public void execute(final RequestMonitor requestMonitor) {
try {
- @SuppressWarnings("unchecked")
- List p = fLaunch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_SOLIB_PATH,
- new ArrayList(1));
+ List p = fGDBBackend.getSharedLibraryPaths();
+
if (p.size() > 0) {
String[] paths = p.toArray(new String[p.size()]);
fCommandControl.queueCommand(
@@ -508,8 +476,10 @@ public class FinalLaunchSequence extends Sequence {
SessionType fSessionType;
boolean fAttach;
- IGDBControl fCommandControl;
- IMIProcesses fProcService;
+ private IGDBControl fCommandControl;
+ private IGDBBackend fGDBBackend;
+ private IMIProcesses fProcService;
+
DsfServicesTracker fTracker;
public FinalLaunchSequence(DsfExecutor executor, GdbLaunch launch, SessionType sessionType, boolean attach) {
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/GdbLaunchDelegate.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/GdbLaunchDelegate.java
index c09b6545bba..c44642c2d96 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/GdbLaunchDelegate.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/GdbLaunchDelegate.java
@@ -323,7 +323,8 @@ public class GdbLaunchDelegate extends LaunchConfigurationDelegate
return false;
}
- private IDsfDebugServicesFactory newServiceFactory(String version) {
+ // A subclass can override this method and provide its own ServiceFactory.
+ protected IDsfDebugServicesFactory newServiceFactory(String version) {
if (isNonStopSession && isNonStopSupported(version)) {
return new GdbDebugServicesFactoryNS(version);
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/ServicesLaunchSequence.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/ServicesLaunchSequence.java
index f387fb93f44..1a145848d97 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/ServicesLaunchSequence.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/ServicesLaunchSequence.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Wind River Systems - initial API and implementation
+ * Nokia - created GDBBackend service. Sep. 2008
*******************************************************************************/
package org.eclipse.dd.gdb.internal.provisional.launching;
@@ -27,12 +28,21 @@ import org.eclipse.dd.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
import org.eclipse.dd.dsf.debug.service.command.ICommandControlService;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.mi.service.CSourceLookup;
+import org.eclipse.dd.mi.service.IMIBackend;
import org.eclipse.dd.mi.service.IMIProcesses;
import org.eclipse.dd.mi.service.MIBreakpointsManager;
public class ServicesLaunchSequence extends Sequence {
Step[] fSteps = new Step[] {
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Create the back end GDB service.
+ //
+ fLaunch.getServiceFactory().createService(IMIBackend.class, fSession, fLaunch.getLaunchConfiguration()).initialize(requestMonitor);
+ }
+ },
// Create and initialize the Connection service.
new Step() {
@Override
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/ShutdownSequence.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/ShutdownSequence.java
index 2da3414a74f..024b16399a6 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/ShutdownSequence.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/ShutdownSequence.java
@@ -30,6 +30,7 @@ import org.eclipse.dd.dsf.debug.service.command.ICommandControl;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.gdb.internal.GdbPlugin;
+import org.eclipse.dd.mi.service.IMIBackend;
import org.eclipse.dd.mi.service.MIBreakpointsManager;
public class ShutdownSequence extends Sequence {
@@ -126,6 +127,11 @@ public class ShutdownSequence extends Sequence {
public void execute(RequestMonitor requestMonitor) {
shutdownService(ICommandControl.class, requestMonitor);
}
+ }, new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(IMIBackend.class, requestMonitor);
+ }
}, new Step() {
@Override
public void execute(RequestMonitor requestMonitor) {
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBBackend.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBBackend.java
new file mode 100644
index 00000000000..14b570f2c83
--- /dev/null
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBBackend.java
@@ -0,0 +1,556 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems, Nokia 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Ling Wang (Nokia) - initial API and implementation with some code moved from GDBControl.
+ * Wind River System
+ * Ericsson
+ *******************************************************************************/
+package org.eclipse.dd.gdb.internal.provisional.service;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.utils.spawner.ProcessFactory;
+import org.eclipse.cdt.utils.spawner.Spawner;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.variables.VariablesPlugin;
+import org.eclipse.dd.dsf.concurrent.DsfRunnable;
+import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.dd.dsf.concurrent.RequestMonitor;
+import org.eclipse.dd.dsf.concurrent.Sequence;
+import org.eclipse.dd.dsf.service.AbstractDsfService;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.gdb.internal.GdbPlugin;
+import org.eclipse.dd.gdb.internal.provisional.IGDBLaunchConfigurationConstants;
+import org.eclipse.dd.gdb.internal.provisional.launching.LaunchUtils;
+import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.InitializationShutdownStep;
+import org.eclipse.dd.mi.service.IMIBackend;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Implementation of {@link IGDBBackend} for the common case where GDB is launched
+ * in local file system on host PC where Eclipse runs. This also manages some GDB parameters
+ * from a given launch configuration.
+ *
+ * You can subclass for you special needs.
+ *
+ * @since 1.1
+ */
+public class GDBBackend extends AbstractDsfService implements IGDBBackend {
+
+ private ILaunchConfiguration fLaunchConfiguration;
+
+ /**
+ * Command line to start GDB.
+ */
+ private List fGDBCommandLine;
+
+ /*
+ * Parameters for launching GDB.
+ */
+ private IPath fProgramPath;
+ private IPath fGDBWorkingDirectory;
+ private String fGDBInitFile;
+ private List fSharedLibPaths;
+ private String fProgramArguments;
+
+ /**
+ * Unique ID of this service instance.
+ */
+ private final String fBackendId;
+ private static int fgInstanceCounter = 0;
+
+ /*
+ * Service state parameters.
+ */
+ private MonitorJob fMonitorJob;
+ private Process fProcess;
+ private int fGDBExitValue;
+ private int fGDBLaunchTimeout = 30;
+
+ public GDBBackend(DsfSession session, ILaunchConfiguration lc) {
+ super(session);
+ fBackendId = "gdb[" +Integer.toString(fgInstanceCounter++) + "]"; //$NON-NLS-1$//$NON-NLS-2$
+ fLaunchConfiguration = lc;
+
+ try {
+ ICProject cproject = LaunchUtils.verifyCProject(lc);
+ fProgramPath = LaunchUtils.verifyProgramPath(lc, cproject);
+ } catch (CoreException e) {
+ fProgramPath = new Path(""); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize( new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(requestMonitor);
+ }
+ });
+ }
+
+ public void doInitialize(final RequestMonitor requestMonitor) {
+
+ final Sequence.Step[] initializeSteps = new Sequence.Step[] {
+ new GDBProcessStep(InitializationShutdownStep.Direction.INITIALIZING),
+ new MonitorJobStep(InitializationShutdownStep.Direction.INITIALIZING),
+ new RegisterStep(InitializationShutdownStep.Direction.INITIALIZING),
+ };
+
+ Sequence startupSequence = new Sequence(getExecutor(), requestMonitor) {
+ @Override public Step[] getSteps() { return initializeSteps; }
+ };
+ getExecutor().execute(startupSequence);
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor requestMonitor) {
+ final Sequence.Step[] shutdownSteps = new Sequence.Step[] {
+ new RegisterStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
+ new MonitorJobStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
+ new GDBProcessStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
+ };
+ Sequence shutdownSequence = new Sequence(getExecutor(), requestMonitor) {
+ @Override public Step[] getSteps() { return shutdownSteps; }
+ };
+ getExecutor().execute(shutdownSequence);
+ }
+
+
+ private IPath getGDBPath() {
+ IPath retVal = new Path(IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT);
+ try {
+ retVal = new Path(fLaunchConfiguration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME,
+ IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT));
+ } catch (CoreException e) {
+ }
+ return retVal;
+ }
+
+ public List getGDBCommandLine() {
+ if (fGDBCommandLine == null)
+ {
+ fGDBCommandLine = new ArrayList();
+
+ // The goal here is to keep options to an absolute minimum.
+ // All configuration should be done in the launch sequence
+ // to allow for easy overriding.
+ fGDBCommandLine.add(getGDBPath().toOSString());
+ fGDBCommandLine.add("--interpreter"); //$NON-NLS-1$
+ fGDBCommandLine.add("mi"); //$NON-NLS-1$
+ // Don't read the gdbinit file here. It is read explicitly in
+ // the LaunchSequence to make it easier to customize.
+ fGDBCommandLine.add("--nx"); //$NON-NLS-1$
+ }
+
+ return fGDBCommandLine;
+ }
+
+ public String getGDBInitFile() throws CoreException {
+ if (fGDBInitFile == null) {
+ fGDBInitFile = fLaunchConfiguration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, ""); //$NON-NLS-1$
+ }
+
+ return fGDBInitFile;
+ }
+
+ public IPath getGDBWorkingDirectory() throws CoreException {
+ if (fGDBWorkingDirectory == null) {
+
+ // First try to use the user-sepcified working directory for the debugged program.
+ // This is fine only with local debug.
+ // For remote debug, the working dir of the debugged program will be on remote device
+ // and hence not applicable. In such case we may just use debugged program path on host
+ // as the working dir for GDB.
+ // However, we cannot find a standard/common way to distinguish remote debug from local
+ // debug. For instance, a local debug may also use gdbserver+gdb. So it's up to each
+ // debugger implementation to make the distinction.
+ //
+ IPath path = null;
+ String location = fLaunchConfiguration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, (String)null);
+
+ if (location != null) {
+ String expandedLocation = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(location);
+ if (expandedLocation.length() > 0) {
+ path = new Path(expandedLocation);
+ }
+ }
+
+ if (path != null) {
+ // Some validity check. Should have been done by UI code.
+ if (path.isAbsolute()) {
+ File dir = new File(path.toPortableString());
+ if (! dir.isDirectory())
+ path = null;
+ } else {
+ IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
+ if (res instanceof IContainer && res.exists()) {
+ path = res.getLocation();
+ }
+ else
+ // Relative but not found in workspace.
+ path = null;
+ }
+ }
+
+ if (path == null) {
+ // default working dir is the project if this config has a project
+ ICProject cp = LaunchUtils.getCProject(fLaunchConfiguration);
+ if (cp != null) {
+ IProject p = cp.getProject();
+ path = p.getLocation();
+ }
+ else {
+ // no meaningful value found. Just return null.
+ }
+ }
+
+ fGDBWorkingDirectory = path;
+ }
+
+ return fGDBWorkingDirectory;
+ }
+
+ public String getProgramArguments() throws CoreException {
+ if (fProgramArguments == null) {
+ fProgramArguments = fLaunchConfiguration.getAttribute(
+ ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
+ (String)null);
+
+ if (fProgramArguments != null)
+ fProgramArguments = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(fProgramArguments);
+ }
+
+ return fProgramArguments;
+ }
+
+ public IPath getProgramPath() {
+ return fProgramPath;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getSharedLibraryPaths() throws CoreException {
+ if (fSharedLibPaths == null) {
+ fSharedLibPaths = fLaunchConfiguration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_SOLIB_PATH,
+ new ArrayList(0));
+ }
+
+ return fSharedLibPaths;
+ }
+
+ /*
+ * Launch GDB process.
+ * Allow subclass to override.
+ */
+ protected Process launchGDBProcess() throws CoreException {
+ List gdbCmdLine = getGDBCommandLine();
+ String[] commandLine = gdbCmdLine.toArray(new String[gdbCmdLine.size()]);
+
+ Process proc = null;
+ try {
+ proc = ProcessFactory.getFactory().exec(commandLine);
+ } catch (IOException e) {
+ String message = "Error while launching command " + gdbCmdLine.toString(); //$NON-NLS-1$
+ throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, message, e));
+ }
+
+ return proc;
+ }
+
+ public Process getProcess() {
+ return fProcess;
+ }
+
+ public OutputStream getMIOutputStream() {
+ return fProcess.getOutputStream();
+ };
+
+ public InputStream getMIInputStream() {
+ return fProcess.getInputStream();
+ };
+
+ public String getId() {
+ return fBackendId;
+ }
+
+ public void interrupt() {
+ if (fProcess instanceof Spawner) {
+ Spawner gdbSpawner = (Spawner) fProcess;
+ gdbSpawner.interrupt();
+ }
+ }
+
+ public void destroy() {
+ if (getState() != State.STARTED)
+ return;
+
+ // destroy() should be supported even if it's not spawner.
+ fProcess.destroy();
+ /*
+ if (fProcess instanceof Spawner) {
+ Spawner gdbSpawner = (Spawner) fProcess;
+ gdbSpawner.destroy();
+ }
+ */
+ }
+
+ public State getState() {
+ if (fMonitorJob == null) {
+ return State.NOT_INITIALIZED;
+ } else if (fMonitorJob.fExited) {
+ return State.TERMINATED;
+ } else {
+ return State.STARTED;
+ }
+ }
+
+ public int getExitCode() {
+ return fGDBExitValue;
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return GdbPlugin.getBundleContext();
+ }
+
+ protected class GDBProcessStep extends InitializationShutdownStep {
+ GDBProcessStep(Direction direction) { super(direction); }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ class GDBLaunchMonitor {
+ boolean fLaunched = false;
+ boolean fTimedOut = false;
+ }
+ final GDBLaunchMonitor fGDBLaunchMonitor = new GDBLaunchMonitor();
+
+ final RequestMonitor gdbLaunchRequestMonitor = new RequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (!fGDBLaunchMonitor.fTimedOut) {
+ fGDBLaunchMonitor.fLaunched = true;
+ if (!isSuccess()) {
+ requestMonitor.setStatus(getStatus());
+ }
+ requestMonitor.done();
+ }
+ }
+ };
+
+ final Job startGdbJob = new Job("Start GDB Process Job") { //$NON-NLS-1$
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ List commandList = getGDBCommandLine();
+
+ try {
+ fProcess = launchGDBProcess();
+ } catch(CoreException e) {
+ String message = "Error while launching command " + commandList.toString(); //$NON-NLS-1$
+ gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, message, e));
+ gdbLaunchRequestMonitor.done();
+ return Status.OK_STATUS;
+ }
+
+ try {
+ InputStream stream = fProcess.getInputStream();
+ Reader r = new InputStreamReader(stream);
+ BufferedReader reader = new BufferedReader(r);
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ //System.out.println("GDB " + line);
+ if (line.endsWith("(gdb)")) { //$NON-NLS-1$
+ break;
+ }
+ }
+ } catch (IOException e) {
+ gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Error reading GDB STDOUT", e)); //$NON-NLS-1$
+ gdbLaunchRequestMonitor.done();
+ return Status.OK_STATUS;
+ }
+
+ gdbLaunchRequestMonitor.done();
+ return Status.OK_STATUS;
+ }
+ };
+ startGdbJob.schedule();
+
+ getExecutor().schedule(new Runnable() {
+ public void run() {
+ // Only process the event if we have not finished yet (hit the breakpoint).
+ if (!fGDBLaunchMonitor.fLaunched) {
+ fGDBLaunchMonitor.fTimedOut = true;
+ Thread jobThread = startGdbJob.getThread();
+ if (jobThread != null) {
+ jobThread.interrupt();
+ }
+ requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, "Timed out trying to launch GDB.", null)); //$NON-NLS-1$
+ requestMonitor.done();
+ }
+ }},
+ fGDBLaunchTimeout, TimeUnit.SECONDS);
+ }
+
+ @Override
+ protected void shutdown(final RequestMonitor requestMonitor) {
+ new Job("Terminating GDB process.") { //$NON-NLS-1$
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ destroy();
+
+ int attempts = 0;
+ while (attempts < 10) {
+ try {
+ // Don't know if we really need the exit value... but what the hell.
+ fGDBExitValue = fProcess.exitValue(); // throws exception if process not exited
+
+ requestMonitor.done();
+ return Status.OK_STATUS;
+ } catch (IllegalThreadStateException ie) {
+ }
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ }
+ attempts++;
+ }
+ requestMonitor.setStatus(new Status(
+ IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Process terminate failed", null)); //$NON-NLS-1$
+ requestMonitor.done();
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+ }
+
+ protected class MonitorJobStep extends InitializationShutdownStep {
+ MonitorJobStep(Direction direction) { super(direction); }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ fMonitorJob = new MonitorJob(
+ fProcess,
+ new DsfRunnable() {
+ public void run() {
+ requestMonitor.done();
+ }
+ });
+ fMonitorJob.schedule();
+ }
+
+ @Override
+ protected void shutdown(RequestMonitor requestMonitor) {
+ if (!fMonitorJob.fExited) {
+ fMonitorJob.kill();
+ }
+ requestMonitor.done();
+ }
+ }
+
+ protected class RegisterStep extends InitializationShutdownStep {
+ RegisterStep(Direction direction) { super(direction); }
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ register(
+ new String[]{ IMIBackend.class.getName(),
+ IGDBBackend.class.getName() },
+ new Hashtable());
+
+ /*
+ * This event is not consumed by any one at present, instead it's
+ * the GDBControlInitializedDMEvent that's used to indicate that GDB
+ * back end is ready for MI commands. But we still fire the event as
+ * it does no harm and may be needed sometime.... 09/29/08
+ */
+ getSession().dispatchEvent(
+ new BackendStateChangedEvent(getSession().getId(), getId(), IMIBackend.State.STARTED),
+ getProperties());
+
+ requestMonitor.done();
+ }
+
+ @Override
+ protected void shutdown(RequestMonitor requestMonitor) {
+ unregister();
+ requestMonitor.done();
+ }
+ }
+
+ /**
+ * Monitors a system process, waiting for it to terminate, and
+ * then notifies the associated runtime process.
+ */
+ private class MonitorJob extends Job {
+ boolean fExited = false;
+ DsfRunnable fMonitorStarted;
+ Process fMonProcess;
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ synchronized(fMonProcess) {
+ getExecutor().submit(fMonitorStarted);
+ while (!fExited) {
+ try {
+ fMonProcess.waitFor();
+ fGDBExitValue = fMonProcess.exitValue();
+ } catch (InterruptedException ie) {
+ // clear interrupted state
+ Thread.interrupted();
+ } finally {
+ fExited = true;
+ getSession().dispatchEvent(
+ new BackendStateChangedEvent(getSession().getId(), getId(), IMIBackend.State.TERMINATED),
+ getProperties());
+ }
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ MonitorJob(Process process, DsfRunnable monitorStarted) {
+ super("GDB process monitor job."); //$NON-NLS-1$
+ fMonProcess = process;
+ fMonitorStarted = monitorStarted;
+ setSystem(true);
+ }
+
+ void kill() {
+ synchronized(fMonProcess) {
+ if (!fExited) {
+ getThread().interrupt();
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl.java
index b92409a9ce2..fca23b8fa31 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl.java
@@ -8,6 +8,7 @@
* Contributors:
* Wind River Systems - initial API and implementation
* Ericsson AB - Modified for additional functionality
+ * Nokia - create and use backend service.
*******************************************************************************/
package org.eclipse.dd.gdb.internal.provisional.service;
@@ -29,7 +30,6 @@ import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.dd.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.gdb.internal.GdbPlugin;
-import org.eclipse.dd.gdb.internal.provisional.service.command.IGDBControl;
import org.eclipse.dd.mi.service.IMIExecutionDMContext;
import org.eclipse.dd.mi.service.IMIProcesses;
import org.eclipse.dd.mi.service.MIRunControl;
@@ -37,7 +37,7 @@ import org.eclipse.dd.mi.service.command.events.MIEvent;
import org.eclipse.dd.mi.service.command.events.MIThreadExitEvent;
public class GDBRunControl extends MIRunControl {
- private IGDBControl fGdb;
+ private IGDBBackend fGdb;
private IMIProcesses fProcService;
// Record list of execution contexts
@@ -60,7 +60,7 @@ public class GDBRunControl extends MIRunControl {
private void doInitialize(final RequestMonitor requestMonitor) {
- fGdb = getServicesTracker().getService(IGDBControl.class);
+ fGdb = getServicesTracker().getService(IGDBBackend.class);
fProcService = getServicesTracker().getService(IMIProcesses.class);
register(new String[]{IRunControl.class.getName(),
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl_7_0.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl_7_0.java
index 1e713542c25..a4ca10cf994 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl_7_0.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl_7_0.java
@@ -9,6 +9,7 @@
* Wind River Systems - initial API and implementation
* Ericsson - Modified for additional functionality
* Ericsson - Version 7.0
+ * Nokia - create and use backend service.
*******************************************************************************/
package org.eclipse.dd.gdb.internal.provisional.service;
@@ -27,13 +28,12 @@ import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.dd.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.gdb.internal.GdbPlugin;
-import org.eclipse.dd.gdb.internal.provisional.service.command.IGDBControl;
import org.eclipse.dd.mi.service.IMIExecutionDMContext;
import org.eclipse.dd.mi.service.IMIProcesses;
import org.eclipse.dd.mi.service.MIRunControl;
public class GDBRunControl_7_0 extends MIRunControl {
- private IGDBControl fGdb;
+ private IGDBBackend fGdb;
private IMIProcesses fProcService;
public GDBRunControl_7_0(DsfSession session) {
@@ -52,7 +52,7 @@ public class GDBRunControl_7_0 extends MIRunControl {
private void doInitialize(final RequestMonitor requestMonitor) {
- fGdb = getServicesTracker().getService(IGDBControl.class);
+ fGdb = getServicesTracker().getService(IGDBBackend.class);
fProcService = getServicesTracker().getService(IMIProcesses.class);
register(new String[]{IRunControl.class.getName(), MIRunControl.class.getName()},
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactory.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactory.java
index 93989b1966b..00c45919f22 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactory.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactory.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Nokia - create and use backend service.
*******************************************************************************/
package org.eclipse.dd.gdb.internal.provisional.service;
@@ -28,6 +29,7 @@ import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl;
import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl_7_0;
import org.eclipse.dd.mi.service.CSourceLookup;
import org.eclipse.dd.mi.service.ExpressionService;
+import org.eclipse.dd.mi.service.IMIBackend;
import org.eclipse.dd.mi.service.MIBreakpoints;
import org.eclipse.dd.mi.service.MIBreakpointsManager;
import org.eclipse.dd.mi.service.MIDisassembly;
@@ -52,13 +54,21 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
public V createService(Class clazz, DsfSession session, Object ... optionalArguments) {
if (MIBreakpointsManager.class.isAssignableFrom(clazz)) {
return (V)createBreakpointManagerService(session);
- } else if (ICommandControl.class.isAssignableFrom(clazz)) {
+ }
+ else if (ICommandControl.class.isAssignableFrom(clazz)) {
for (Object arg : optionalArguments) {
if (arg instanceof ILaunchConfiguration) {
return (V)createCommandControl(session, (ILaunchConfiguration)arg);
}
}
}
+ else if (IMIBackend.class.isAssignableFrom(clazz)) {
+ for (Object arg : optionalArguments) {
+ if (arg instanceof ILaunchConfiguration) {
+ return (V)createBackendGDBService(session, (ILaunchConfiguration)arg);
+ }
+ }
+ }
return super.createService(clazz, session);
@@ -80,6 +90,10 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
return new GDBControl(session, config);
}
+ protected IMIBackend createBackendGDBService(DsfSession session, ILaunchConfiguration lc) {
+ return new GDBBackend(session, lc);
+ }
+
@Override
protected IDisassembly createDisassemblyService(DsfSession session) {
return new MIDisassembly(session);
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/IGDBBackend.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/IGDBBackend.java
new file mode 100644
index 00000000000..565f8220698
--- /dev/null
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/IGDBBackend.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Nokia Corporation.
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Ling Wang (Nokia) - initial version. Sep, 2008
+ *******************************************************************************/
+package org.eclipse.dd.gdb.internal.provisional.service;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.dd.mi.service.IMIBackend;
+
+/**
+ * Service that manages back end GDB process, such as launching and monitoring
+ * GDB process, managing certain GDB parameters/options. This service makes it
+ * easy for debugger implementations to customize the way to start GDB process
+ * and convert some parameters if needed. See bug 240092 for more.
+ *
+ * A base implementation {@link GDBBackend} is provided that should be
+ * sufficient for most cases. But if you have special needs, it's recommended to
+ * subclass the base implementation.
+ *
+ * Here are some special cases:
+ * Example #1: GDB is usually launched on the host machine where Eclipse is
+ * running, but it can also be launched on a remote machine through, say, SSH.
+ * Example #2: GDB is usually launched in the host file system, but it can also
+ * be launched in a chroot'ed file system such as Scratchbox (see
+ * http://www.scratchbox.org)
+ *
+ * @since 1.1
+ */
+public interface IGDBBackend extends IMIBackend {
+
+
+ /**
+ * Return the command line that is used to launch GDB.
+ * Note it's not needed to put debugged binary in the command, as that will
+ * be set by a MI command.
+ *
+ * @return
+ */
+ public List getGDBCommandLine();
+
+ /**
+ * Get path of the debugged program on host.
+ *
+ * @return IPath
+ */
+ public IPath getProgramPath();
+
+ /**
+ * Get init file for GDB.
+ *
+ * @return file name, may have relative or absolute path, or empty string
+ * ("") indicating an init file is not specified.
+ * @throws CoreException
+ * - error in getting the option.
+ */
+ public String getGDBInitFile() throws CoreException;
+
+ /**
+ * get arguments for the debugged program.
+ *
+ * @return String
+ * @throws CoreException
+ * - error in getting the option.
+ */
+ public String getProgramArguments() throws CoreException;
+
+ /**
+ * Get working directory for GDB.
+ *
+ * @return IPath - null if no meaningful value found.
+ * @throws CoreException
+ * - if any error occurs.
+ */
+ public IPath getGDBWorkingDirectory() throws CoreException;
+
+ /**
+ * @throws CoreException
+ * - error in getting the option.
+ */
+ public List getSharedLibraryPaths() throws CoreException;
+
+
+ /**
+ * Sends an interrupt signal to the GDB process.
+ */
+ public void interrupt();
+}
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBCLIProcess.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBCLIProcess.java
deleted file mode 100644
index 3823b1e5175..00000000000
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBCLIProcess.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2008 Wind River Systems and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Wind River Systems - initial API and implementation
- *******************************************************************************/
-package org.eclipse.dd.gdb.internal.provisional.service.command;
-
-import java.io.IOException;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.RejectedExecutionException;
-
-import org.eclipse.dd.dsf.concurrent.DsfRunnable;
-import org.eclipse.dd.dsf.debug.service.command.ICommandControlService;
-import org.eclipse.dd.dsf.service.DsfSession;
-import org.eclipse.dd.mi.service.command.AbstractCLIProcess;
-
-/**
- *
- */
-class GDBCLIProcess extends AbstractCLIProcess {
-
- public GDBCLIProcess(ICommandControlService commandControl) throws IOException {
- super(commandControl);
- }
-
-
- /**
- * @see java.lang.Process#waitFor()
- */
- @Override
- public int waitFor() throws InterruptedException {
- if (!DsfSession.isSessionActive(getSession().getId())) return 0;
-
- Process process = null;
- try {
- process = getSession().getExecutor().submit(new Callable() {
- public Process call() throws Exception {
- if (isDisposed()) return null;
- return ((IGDBControl)getCommandControlService()).getGDBProcess();
- }}).get();
- } catch (RejectedExecutionException e) {
- } catch (ExecutionException e) {
- }
- if (process == null) return 0;
- return process.waitFor();
- }
-
-
- /**
- * @see java.lang.Process#exitValue()
- */
- @Override
- public int exitValue() {
- if (!DsfSession.isSessionActive(getSession().getId())) return 0;
- try {
- return getSession().getExecutor().submit(new Callable() {
- public Integer call() throws Exception {
- if (!DsfSession.isSessionActive(getSession().getId())) {
- return new Integer(-1);
- } else {
- if (isDisposed()) return new Integer(-1);
- IGDBControl gdb = (IGDBControl)getCommandControlService();
- if (!gdb.isGDBExited()) {
- throw new IllegalThreadStateException("GDB Process has not exited"); //$NON-NLS-1$
- }
- return gdb.getGDBExitCode();
- }
- }}).get().intValue();
- } catch (RejectedExecutionException e) {
- } catch (InterruptedException e) {
- } catch (ExecutionException e) {
- if (e.getCause() instanceof RuntimeException) {
- throw (RuntimeException)e.getCause();
- }
- }
- return 0;
- }
- /**
- * @see java.lang.Process#destroy()
- */
- @Override
- public void destroy() {
- try {
- getSession().getExecutor().execute(new DsfRunnable() { public void run() {
- if (!DsfSession.isSessionActive(getSession().getId())) return;
- if (isDisposed()) return;
- IGDBControl gdb = (IGDBControl)getCommandControlService();
- gdb.destroy();
- }});
- } catch (RejectedExecutionException e) {
- // Session disposed.
- }
- }
-
-
-}
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java
index 9a05c09c80d..efb573b7934 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java
@@ -8,31 +8,21 @@
* Contributors:
* Wind River Systems - initial API and implementation
* Ericsson - Modified for additional features in DSF Reference implementation
+ * Nokia - create and use backend service.
*******************************************************************************/
package org.eclipse.dd.gdb.internal.provisional.service.command;
-import java.io.BufferedReader;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
import java.util.Hashtable;
-import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.utils.pty.PTY;
-import org.eclipse.cdt.utils.spawner.ProcessFactory;
-import org.eclipse.cdt.utils.spawner.Spawner;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
@@ -49,13 +39,17 @@ import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.gdb.internal.GdbPlugin;
import org.eclipse.dd.gdb.internal.provisional.launching.GdbLaunch;
import org.eclipse.dd.gdb.internal.provisional.launching.LaunchUtils;
+import org.eclipse.dd.gdb.internal.provisional.service.IGDBBackend;
import org.eclipse.dd.gdb.internal.provisional.service.SessionType;
+import org.eclipse.dd.mi.service.IMIBackend;
import org.eclipse.dd.mi.service.IMIProcesses;
import org.eclipse.dd.mi.service.MIProcesses;
+import org.eclipse.dd.mi.service.IMIBackend.BackendStateChangedEvent;
import org.eclipse.dd.mi.service.MIProcesses.ContainerStartedDMEvent;
import org.eclipse.dd.mi.service.command.AbstractCLIProcess;
import org.eclipse.dd.mi.service.command.AbstractMIControl;
import org.eclipse.dd.mi.service.command.CLIEventProcessor;
+import org.eclipse.dd.mi.service.command.MIBackendCLIProcess;
import org.eclipse.dd.mi.service.command.MIControlDMContext;
import org.eclipse.dd.mi.service.command.MIInferiorProcess;
import org.eclipse.dd.mi.service.command.MIRunControlEventProcessor;
@@ -74,7 +68,7 @@ import org.osgi.framework.BundleContext;
/**
* GDB Debugger control implementation. This implementation extends the
* base MI control implementation to provide the GDB-specific debugger
- * features. This includes:
+ * features. This includes:
* - CLI console support,
* - inferior process status tracking.
*/
@@ -92,7 +86,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
}
/**
- * Event indicating that the back end process has terminated.
+ * Event indicating that the CommandControl (back end process) has terminated.
*/
private static class GDBControlShutdownDMEvent extends AbstractDMEvent
implements ICommandControlShutdownDMEvent
@@ -102,22 +96,16 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
}
}
- private static int fgInstanceCounter = 0;
- private final GDBControlDMContext fControlDmc;
+ private GDBControlDMContext fControlDmc;
private SessionType fSessionType;
private boolean fAttach;
+
+ private IGDBBackend fMIBackend;
private boolean fConnected = true;
- private MonitorJob fMonitorJob;
- private IPath fGdbPath;
- private IPath fExecPath;
- private Process fProcess;
- private int fGDBExitValue;
- private int fGDBLaunchTimeout = 30;
-
private MIRunControlEventProcessor fMIEventProcessor;
private CLIEventProcessor fCLICommandProcessor;
private AbstractCLIProcess fCLIProcess;
@@ -126,16 +114,9 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
private PTY fPty;
public GDBControl(DsfSession session, ILaunchConfiguration config) {
- super(session, "gdbcontrol[" + ++fgInstanceCounter + "]", false); //$NON-NLS-1$ //$NON-NLS-2$
+ super(session, false);
fSessionType = LaunchUtils.getSessionType(config);
fAttach = LaunchUtils.getIsAttach(config);
- fGdbPath = LaunchUtils.getGDBPath(config);
- try {
- fExecPath = LaunchUtils.verifyProgramPath(config, LaunchUtils.getCProject(config));
- } catch (CoreException e) {
- fExecPath = new Path(""); //$NON-NLS-1$
- }
- fControlDmc = new GDBControlDMContext(session.getId(), getId());
}
@Override
@@ -154,9 +135,14 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
}
public void doInitialize(final RequestMonitor requestMonitor) {
+
+ fMIBackend = getServicesTracker().getService(IGDBBackend.class);
+
+ // getId uses the MIBackend service, which is why we must wait until we
+ // have it, before we can create this context.
+ fControlDmc = new GDBControlDMContext(getSession().getId(), getId());
+
final Sequence.Step[] initializeSteps = new Sequence.Step[] {
- new GDBProcessStep(InitializationShutdownStep.Direction.INITIALIZING),
- new MonitorJobStep(InitializationShutdownStep.Direction.INITIALIZING),
new CommandMonitoringStep(InitializationShutdownStep.Direction.INITIALIZING),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.INITIALIZING),
new CommandProcessorsStep(InitializationShutdownStep.Direction.INITIALIZING),
@@ -176,8 +162,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
new CommandProcessorsStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new CommandMonitoringStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
- new MonitorJobStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
- new GDBProcessStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
};
Sequence shutdownSequence = new Sequence(getExecutor(), requestMonitor) {
@Override public Step[] getSteps() { return shutdownSteps; }
@@ -186,6 +170,10 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
}
+ public String getId() {
+ return fMIBackend.getId();
+ }
+
@Override
public MIControlDMContext getControlDMContext() {
return fControlDmc;
@@ -202,23 +190,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
public boolean getIsAttachSession() {
return fAttach;
}
- public boolean canInterrupt() {
- return fProcess instanceof Spawner;
- }
-
- public void interrupt() {
- if (fProcess instanceof Spawner) {
- Spawner gdbSpawner = (Spawner) fProcess;
- gdbSpawner.interrupt();
- }
- }
-
- public void destroy() {
- if (fProcess instanceof Spawner) {
- Spawner gdbSpawner = (Spawner) fProcess;
- gdbSpawner.destroy();
- }
- }
public void terminate(final RequestMonitor rm) {
// Schedule a runnable to be executed 2 seconds from now.
@@ -227,9 +198,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
final Future> quitTimeoutFuture = getExecutor().schedule(
new DsfRunnable() {
public void run() {
- if (!isGDBExited()) {
- destroy();
- }
+ fMIBackend.destroy();
rm.done();
}
@@ -240,16 +209,15 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
},
2, TimeUnit.SECONDS);
- MIGDBExit cmd = new MIGDBExit(fControlDmc);
queueCommand(
- cmd,
+ new MIGDBExit(fControlDmc),
new DataRequestMonitor(getExecutor(), rm) {
@Override
public void handleCompleted() {
// Cancel the time out runnable (if it hasn't run yet).
if (quitTimeoutFuture.cancel(false)) {
- if (!isSuccess() && !isGDBExited()) {
- destroy();
+ if (!isSuccess()) {
+ fMIBackend.destroy();
}
rm.done();
}
@@ -276,7 +244,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
// Tell GDB to use this PTY
queueCommand(
- new MIInferiorTTYSet(fControlDmc, fPty.getSlaveName()),
+ new MIInferiorTTYSet((ICommandControlDMContext)fControlDmc, fPty.getSlaveName()),
new DataRequestMonitor(getExecutor(), requestMonitor) {
@Override
protected void handleFailure() {
@@ -396,9 +364,9 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
*/
public void createInferiorProcess() {
if (fPty == null) {
- fInferiorProcess = new GDBInferiorProcess(GDBControl.this, fProcess.getOutputStream());
+ fInferiorProcess = new GDBInferiorProcess(GDBControl.this, fMIBackend, fMIBackend.getMIOutputStream());
} else {
- fInferiorProcess = new GDBInferiorProcess(GDBControl.this, fPty);
+ fInferiorProcess = new GDBInferiorProcess(GDBControl.this, fMIBackend, fPty);
}
}
@@ -409,10 +377,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
public void setConnected(boolean connected) {
fConnected = connected;
}
-
- public Process getGDBProcess() {
- return fProcess;
- }
public AbstractCLIProcess getCLIProcess() {
return fCLIProcess;
@@ -422,72 +386,28 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
return fInferiorProcess;
}
- public boolean isGDBExited() {
- return fMonitorJob != null && fMonitorJob.fExited;
- }
-
- public int getGDBExitCode() {
- return fGDBExitValue;
- }
-
- public IPath getExecutablePath() { return fExecPath; }
-
+ public IPath getExecutablePath() { return fMIBackend.getProgramPath(); }
+
+
@DsfServiceEventHandler
public void eventDispatched(ICommandControlShutdownDMEvent e) {
// Handle our "GDB Exited" event and stop processing commands.
stopCommandProcessing();
}
- /**
- * Monitors a system process, waiting for it to terminate, and
- * then notifies the associated runtime process.
- */
- private class MonitorJob extends Job {
- boolean fExited = false;
- DsfRunnable fMonitorStarted;
- Process fMonProcess;
-
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- synchronized(fMonProcess) {
- getExecutor().submit(fMonitorStarted);
- while (!fExited) {
- try {
- fMonProcess.waitFor();
- fGDBExitValue = fMonProcess.exitValue();
- } catch (InterruptedException ie) {
- // clear interrupted state
- Thread.interrupted();
- } finally {
- fExited = true;
- getSession().dispatchEvent(new GDBControlShutdownDMEvent(fControlDmc) {}, getProperties());
- }
- }
- }
- return Status.OK_STATUS;
+ @DsfServiceEventHandler
+ public void eventDispatched(BackendStateChangedEvent e) {
+ if (e.getState() == IMIBackend.State.TERMINATED && e.getBackendId().equals(fMIBackend.getId())) {
+ // Handle "GDB Exited" event, just relay to following event.
+ getSession().dispatchEvent(new GDBControlShutdownDMEvent(fControlDmc), getProperties());
}
-
- MonitorJob(Process process, DsfRunnable monitorStarted) {
- super("GDB process monitor job."); //$NON-NLS-1$
- fMonProcess = process;
- fMonitorStarted = monitorStarted;
- setSystem(true);
- }
-
- void kill() {
- synchronized(fMonProcess) {
- if (!fExited) {
- getThread().interrupt();
- }
- }
- }
- }
-
+ }
+
public static class InitializationShutdownStep extends Sequence.Step {
public enum Direction { INITIALIZING, SHUTTING_DOWN }
private Direction fDirection;
- InitializationShutdownStep(Direction direction) { fDirection = direction; }
+ public InitializationShutdownStep(Direction direction) { fDirection = direction; }
@Override
final public void execute(RequestMonitor requestMonitor) {
@@ -514,161 +434,13 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
requestMonitor.done();
}
}
-
- protected class GDBProcessStep extends InitializationShutdownStep {
- GDBProcessStep(Direction direction) { super(direction); }
-
- @Override
- public void initialize(final RequestMonitor requestMonitor) {
- class GDBLaunchMonitor {
- boolean fLaunched = false;
- boolean fTimedOut = false;
- }
- final GDBLaunchMonitor fGDBLaunchMonitor = new GDBLaunchMonitor();
-
- final RequestMonitor gdbLaunchRequestMonitor = new RequestMonitor(getExecutor(), null) {
- @Override
- protected void handleCompleted() {
- if (!fGDBLaunchMonitor.fTimedOut) {
- fGDBLaunchMonitor.fLaunched = true;
- if (!isSuccess()) {
- requestMonitor.setStatus(getStatus());
- }
- requestMonitor.done();
- }
- }
- };
-
- final Job startGdbJob = new Job("Start GDB Process Job") { //$NON-NLS-1$
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- List commandList = new ArrayList();
-
- // The goal here is to keep options to an absolute minimum.
- // All configuration should be done in the launch sequence
- // to allow for easy overriding.
- commandList.add(fGdbPath.toOSString());
- commandList.add("--interpreter"); //$NON-NLS-1$
- // We currently work with MI version 2
- commandList.add("mi2"); //$NON-NLS-1$
- // Don't read the gdbinit file here. It is read explicitly in
- // the LaunchSequence to make it easier to customize.
- commandList.add("--nx"); //$NON-NLS-1$
-
- String[] commandLine = commandList.toArray(new String[commandList.size()]);
-
- try {
- fProcess = ProcessFactory.getFactory().exec(commandLine);
- } catch(IOException e) {
- String message = "Error while launching command " + commandList.toString(); //$NON-NLS-1$
- gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, message, e));
- gdbLaunchRequestMonitor.done();
- return Status.OK_STATUS;
- }
-
- try {
- InputStream stream = fProcess.getInputStream();
- Reader r = new InputStreamReader(stream);
- BufferedReader reader = new BufferedReader(r);
- String line;
- while ((line = reader.readLine()) != null) {
- line = line.trim();
- //System.out.println("GDB " + line);
- if (line.endsWith("(gdb)")) { //$NON-NLS-1$
- break;
- }
- }
- } catch (IOException e) {
- gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Error reading GDB STDOUT", e)); //$NON-NLS-1$
- gdbLaunchRequestMonitor.done();
- return Status.OK_STATUS;
- }
-
- gdbLaunchRequestMonitor.done();
- return Status.OK_STATUS;
- }
- };
- startGdbJob.schedule();
-
- getExecutor().schedule(new Runnable() {
- public void run() {
- // Only process the event if we have not finished yet (hit the breakpoint).
- if (!fGDBLaunchMonitor.fLaunched) {
- fGDBLaunchMonitor.fTimedOut = true;
- Thread jobThread = startGdbJob.getThread();
- if (jobThread != null) {
- jobThread.interrupt();
- }
- requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, "Timed out trying to launch GDB.", null)); //$NON-NLS-1$
- requestMonitor.done();
- }
- }},
- fGDBLaunchTimeout, TimeUnit.SECONDS);
-
- }
-
- @Override
- protected void shutdown(final RequestMonitor requestMonitor) {
- new Job("Terminating GDB process.") { //$NON-NLS-1$
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- fProcess.destroy();
-
- int attempts = 0;
- while (attempts < 10) {
- try {
- // Don't know if we really need the exit value... but what the hell.
- fGDBExitValue = fProcess.exitValue(); // throws exception if process not exited
-
- requestMonitor.done();
- return Status.OK_STATUS;
- } catch (IllegalThreadStateException ie) {
- }
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- }
- attempts++;
- }
- requestMonitor.setStatus(new Status(
- IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Process terminate failed", null)); //$NON-NLS-1$
- requestMonitor.done();
- return Status.OK_STATUS;
- }
- }.schedule();
- }
- }
- protected class MonitorJobStep extends InitializationShutdownStep {
- MonitorJobStep(Direction direction) { super(direction); }
-
- @Override
- public void initialize(final RequestMonitor requestMonitor) {
- fMonitorJob = new MonitorJob(
- fProcess,
- new DsfRunnable() {
- public void run() {
- requestMonitor.done();
- }
- });
- fMonitorJob.schedule();
- }
-
- @Override
- protected void shutdown(RequestMonitor requestMonitor) {
- if (!fMonitorJob.fExited) {
- fMonitorJob.kill();
- }
- requestMonitor.done();
- }
- }
-
protected class CommandMonitoringStep extends InitializationShutdownStep {
CommandMonitoringStep(Direction direction) { super(direction); }
@Override
protected void initialize(final RequestMonitor requestMonitor) {
- startCommandProcessing(fProcess.getInputStream(), fProcess.getOutputStream());
+ startCommandProcessing(fMIBackend.getMIInputStream(), fMIBackend.getMIOutputStream());
requestMonitor.done();
}
@@ -699,7 +471,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
@Override
public void initialize(final RequestMonitor requestMonitor) {
try {
- fCLIProcess = new GDBCLIProcess(GDBControl.this);
+ fCLIProcess = new MIBackendCLIProcess(GDBControl.this, fMIBackend);
}
catch(IOException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Failed to create CLI Process", e)); //$NON-NLS-1$
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl_7_0.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl_7_0.java
index 822eb54546c..4bc855a24e2 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl_7_0.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl_7_0.java
@@ -12,28 +12,17 @@
*******************************************************************************/
package org.eclipse.dd.gdb.internal.provisional.service.command;
-import java.io.BufferedReader;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
import java.util.Hashtable;
-import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.utils.pty.PTY;
-import org.eclipse.cdt.utils.spawner.ProcessFactory;
-import org.eclipse.cdt.utils.spawner.Spawner;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
@@ -50,12 +39,16 @@ import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.gdb.internal.GdbPlugin;
import org.eclipse.dd.gdb.internal.provisional.launching.GdbLaunch;
import org.eclipse.dd.gdb.internal.provisional.launching.LaunchUtils;
+import org.eclipse.dd.gdb.internal.provisional.service.IGDBBackend;
import org.eclipse.dd.gdb.internal.provisional.service.SessionType;
+import org.eclipse.dd.mi.service.IMIBackend;
import org.eclipse.dd.mi.service.IMIProcesses;
import org.eclipse.dd.mi.service.MIProcesses;
+import org.eclipse.dd.mi.service.IMIBackend.BackendStateChangedEvent;
import org.eclipse.dd.mi.service.command.AbstractCLIProcess;
import org.eclipse.dd.mi.service.command.AbstractMIControl;
import org.eclipse.dd.mi.service.command.CLIEventProcessor_7_0;
+import org.eclipse.dd.mi.service.command.MIBackendCLIProcess;
import org.eclipse.dd.mi.service.command.MIControlDMContext;
import org.eclipse.dd.mi.service.command.MIInferiorProcess;
import org.eclipse.dd.mi.service.command.MIRunControlEventProcessor_7_0;
@@ -74,7 +67,7 @@ import org.osgi.framework.BundleContext;
/**
* GDB Debugger control implementation. This implementation extends the
* base MI control implementation to provide the GDB-specific debugger
- * features. This includes:
+ * features. This includes:
* - CLI console support,
* - inferior process status tracking.
*/
@@ -92,7 +85,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
}
/**
- * Event indicating that the back end process has terminated.
+ * Event indicating that the CommandControl (back end process) has terminated.
*/
private static class GDBControlShutdownDMEvent extends AbstractDMEvent
implements ICommandControlShutdownDMEvent
@@ -102,22 +95,16 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
}
}
- private static int fgInstanceCounter = 0;
- private final GDBControlDMContext fControlDmc;
+ private GDBControlDMContext fControlDmc;
private SessionType fSessionType;
private boolean fAttach;
+ private IGDBBackend fMIBackend;
+
private boolean fConnected = true;
- private MonitorJob fMonitorJob;
- private IPath fGdbPath;
- private IPath fExecPath;
- private Process fProcess;
- private int fGDBExitValue;
- private int fGDBLaunchTimeout = 30;
-
private MIRunControlEventProcessor_7_0 fMIEventProcessor;
private CLIEventProcessor_7_0 fCLICommandProcessor;
private AbstractCLIProcess fCLIProcess;
@@ -126,16 +113,9 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
private PTY fPty;
public GDBControl_7_0(DsfSession session, ILaunchConfiguration config) {
- super(session, "gdbcontrol[" + ++fgInstanceCounter + "]", true); //$NON-NLS-1$ //$NON-NLS-2$
+ super(session, true);
fSessionType = LaunchUtils.getSessionType(config);
fAttach = LaunchUtils.getIsAttach(config);
- fGdbPath = LaunchUtils.getGDBPath(config);
- try {
- fExecPath = LaunchUtils.verifyProgramPath(config, LaunchUtils.getCProject(config));
- } catch (CoreException e) {
- fExecPath = new Path(""); //$NON-NLS-1$
- }
- fControlDmc = new GDBControlDMContext(session.getId(), getId());
}
@Override
@@ -154,9 +134,13 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
}
public void doInitialize(final RequestMonitor requestMonitor) {
+ fMIBackend = getServicesTracker().getService(IGDBBackend.class);
+
+ // getId uses the MIBackend service, which is why we must wait until we
+ // have it, before we can create this context.
+ fControlDmc = new GDBControlDMContext(getSession().getId(), getId());
+
final Sequence.Step[] initializeSteps = new Sequence.Step[] {
- new GDBProcessStep(InitializationShutdownStep.Direction.INITIALIZING),
- new MonitorJobStep(InitializationShutdownStep.Direction.INITIALIZING),
new CommandMonitoringStep(InitializationShutdownStep.Direction.INITIALIZING),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.INITIALIZING),
new CommandProcessorsStep(InitializationShutdownStep.Direction.INITIALIZING),
@@ -176,8 +160,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
new CommandProcessorsStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
new CommandMonitoringStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
- new MonitorJobStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
- new GDBProcessStep(InitializationShutdownStep.Direction.SHUTTING_DOWN),
};
Sequence shutdownSequence = new Sequence(getExecutor(), requestMonitor) {
@Override public Step[] getSteps() { return shutdownSteps; }
@@ -185,6 +167,10 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
getExecutor().execute(shutdownSequence);
}
+
+ public String getId() {
+ return fMIBackend.getId();
+ }
@Override
public MIControlDMContext getControlDMContext() {
@@ -202,23 +188,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
public boolean getIsAttachSession() {
return fAttach;
}
- public boolean canInterrupt() {
- return fProcess instanceof Spawner;
- }
-
- public void interrupt() {
- if (fProcess instanceof Spawner) {
- Spawner gdbSpawner = (Spawner) fProcess;
- gdbSpawner.interrupt();
- }
- }
-
- public void destroy() {
- if (fProcess instanceof Spawner) {
- Spawner gdbSpawner = (Spawner) fProcess;
- gdbSpawner.destroy();
- }
- }
public void terminate(final RequestMonitor rm) {
// Schedule a runnable to be executed 2 seconds from now.
@@ -227,9 +196,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
final Future> quitTimeoutFuture = getExecutor().schedule(
new DsfRunnable() {
public void run() {
- if (!isGDBExited()) {
- destroy();
- }
+ fMIBackend.destroy();
rm.done();
}
@@ -248,8 +215,8 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
public void handleCompleted() {
// Cancel the time out runnable (if it hasn't run yet).
if (quitTimeoutFuture.cancel(false)) {
- if (!isSuccess() && !isGDBExited()) {
- destroy();
+ if (!isSuccess()) {
+ fMIBackend.destroy();
}
rm.done();
}
@@ -276,7 +243,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
// Tell GDB to use this PTY
queueCommand(
- new MIInferiorTTYSet(fControlDmc, fPty.getSlaveName()),
+ new MIInferiorTTYSet((ICommandControlDMContext)fControlDmc, fPty.getSlaveName()),
new DataRequestMonitor(getExecutor(), requestMonitor) {
@Override
protected void handleFailure() {
@@ -390,9 +357,9 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
*/
public void createInferiorProcess() {
if (fPty == null) {
- fInferiorProcess = new GDBInferiorProcess(GDBControl_7_0.this, fProcess.getOutputStream());
+ fInferiorProcess = new GDBInferiorProcess(GDBControl_7_0.this, fMIBackend, fMIBackend.getMIOutputStream());
} else {
- fInferiorProcess = new GDBInferiorProcess(GDBControl_7_0.this, fPty);
+ fInferiorProcess = new GDBInferiorProcess(GDBControl_7_0.this, fMIBackend, fPty);
}
}
@@ -403,10 +370,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
public void setConnected(boolean connected) {
fConnected = connected;
}
-
- public Process getGDBProcess() {
- return fProcess;
- }
public AbstractCLIProcess getCLIProcess() {
return fCLIProcess;
@@ -416,15 +379,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
return fInferiorProcess;
}
- public boolean isGDBExited() {
- return fMonitorJob != null && fMonitorJob.fExited;
- }
-
- public int getGDBExitCode() {
- return fGDBExitValue;
- }
-
- public IPath getExecutablePath() { return fExecPath; }
+ public IPath getExecutablePath() { return fMIBackend.getProgramPath(); }
@DsfServiceEventHandler
public void eventDispatched(ICommandControlShutdownDMEvent e) {
@@ -432,56 +387,19 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
stopCommandProcessing();
}
- /**
- * Monitors a system process, waiting for it to terminate, and
- * then notifies the associated runtime process.
- */
- private class MonitorJob extends Job {
- boolean fExited = false;
- DsfRunnable fMonitorStarted;
- Process fMonProcess;
-
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- synchronized(fMonProcess) {
- getExecutor().submit(fMonitorStarted);
- while (!fExited) {
- try {
- fMonProcess.waitFor();
- fGDBExitValue = fMonProcess.exitValue();
- } catch (InterruptedException ie) {
- // clear interrupted state
- Thread.interrupted();
- } finally {
- fExited = true;
- getSession().dispatchEvent(new GDBControlShutdownDMEvent(fControlDmc) {}, getProperties());
- }
- }
- }
- return Status.OK_STATUS;
+ @DsfServiceEventHandler
+ public void eventDispatched(BackendStateChangedEvent e) {
+ if (e.getState() == IMIBackend.State.TERMINATED && e.getBackendId().equals(fMIBackend.getId())) {
+ // Handle "GDB Exited" event, just relay to following event.
+ getSession().dispatchEvent(new GDBControlShutdownDMEvent(fControlDmc), getProperties());
}
-
- MonitorJob(Process process, DsfRunnable monitorStarted) {
- super("GDB process monitor job."); //$NON-NLS-1$
- fMonProcess = process;
- fMonitorStarted = monitorStarted;
- setSystem(true);
- }
-
- void kill() {
- synchronized(fMonProcess) {
- if (!fExited) {
- getThread().interrupt();
- }
- }
- }
- }
-
+ }
+
public static class InitializationShutdownStep extends Sequence.Step {
public enum Direction { INITIALIZING, SHUTTING_DOWN }
private Direction fDirection;
- InitializationShutdownStep(Direction direction) { fDirection = direction; }
+ public InitializationShutdownStep(Direction direction) { fDirection = direction; }
@Override
final public void execute(RequestMonitor requestMonitor) {
@@ -509,160 +427,12 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
}
}
- protected class GDBProcessStep extends InitializationShutdownStep {
- GDBProcessStep(Direction direction) { super(direction); }
-
- @Override
- public void initialize(final RequestMonitor requestMonitor) {
- class GDBLaunchMonitor {
- boolean fLaunched = false;
- boolean fTimedOut = false;
- }
- final GDBLaunchMonitor fGDBLaunchMonitor = new GDBLaunchMonitor();
-
- final RequestMonitor gdbLaunchRequestMonitor = new RequestMonitor(getExecutor(), null) {
- @Override
- protected void handleCompleted() {
- if (!fGDBLaunchMonitor.fTimedOut) {
- fGDBLaunchMonitor.fLaunched = true;
- if (!isSuccess()) {
- requestMonitor.setStatus(getStatus());
- }
- requestMonitor.done();
- }
- }
- };
-
- final Job startGdbJob = new Job("Start GDB Process Job") { //$NON-NLS-1$
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- List commandList = new ArrayList();
-
- // The goal here is to keep options to an absolute minimum.
- // All configuration should be done in the launch sequence
- // to allow for easy overriding.
- commandList.add(fGdbPath.toOSString());
- commandList.add("--interpreter"); //$NON-NLS-1$
- // We currently work with MI version 2
- commandList.add("mi2"); //$NON-NLS-1$
- // Don't read the gdbinit file here. It is read explicitly in
- // the LaunchSequence to make it easier to customize.
- commandList.add("--nx"); //$NON-NLS-1$
-
- String[] commandLine = commandList.toArray(new String[commandList.size()]);
-
- try {
- fProcess = ProcessFactory.getFactory().exec(commandLine);
- } catch(IOException e) {
- String message = "Error while launching command " + commandList.toString(); //$NON-NLS-1$
- gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, message, e));
- gdbLaunchRequestMonitor.done();
- return Status.OK_STATUS;
- }
-
- try {
- InputStream stream = fProcess.getInputStream();
- Reader r = new InputStreamReader(stream);
- BufferedReader reader = new BufferedReader(r);
- String line;
- while ((line = reader.readLine()) != null) {
- line = line.trim();
- //System.out.println("GDB " + line);
- if (line.endsWith("(gdb)")) { //$NON-NLS-1$
- break;
- }
- }
- } catch (IOException e) {
- gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Error reading GDB STDOUT", e)); //$NON-NLS-1$
- gdbLaunchRequestMonitor.done();
- return Status.OK_STATUS;
- }
-
- gdbLaunchRequestMonitor.done();
- return Status.OK_STATUS;
- }
- };
- startGdbJob.schedule();
-
- getExecutor().schedule(new Runnable() {
- public void run() {
- // Only process the event if we have not finished yet (hit the breakpoint).
- if (!fGDBLaunchMonitor.fLaunched) {
- fGDBLaunchMonitor.fTimedOut = true;
- Thread jobThread = startGdbJob.getThread();
- if (jobThread != null) {
- jobThread.interrupt();
- }
- requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, "Timed out trying to launch GDB.", null)); //$NON-NLS-1$
- requestMonitor.done();
- }
- }},
- fGDBLaunchTimeout, TimeUnit.SECONDS);
-
- }
-
- @Override
- protected void shutdown(final RequestMonitor requestMonitor) {
- new Job("Terminating GDB process.") { //$NON-NLS-1$
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- fProcess.destroy();
-
- int attempts = 0;
- while (attempts < 10) {
- try {
- // Don't know if we really need the exit value... but what the hell.
- fGDBExitValue = fProcess.exitValue(); // throws exception if process not exited
-
- requestMonitor.done();
- return Status.OK_STATUS;
- } catch (IllegalThreadStateException ie) {
- }
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- }
- attempts++;
- }
- requestMonitor.setStatus(new Status(
- IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Process terminate failed", null)); //$NON-NLS-1$
- requestMonitor.done();
- return Status.OK_STATUS;
- }
- }.schedule();
- }
- }
-
- protected class MonitorJobStep extends InitializationShutdownStep {
- MonitorJobStep(Direction direction) { super(direction); }
-
- @Override
- public void initialize(final RequestMonitor requestMonitor) {
- fMonitorJob = new MonitorJob(
- fProcess,
- new DsfRunnable() {
- public void run() {
- requestMonitor.done();
- }
- });
- fMonitorJob.schedule();
- }
-
- @Override
- protected void shutdown(RequestMonitor requestMonitor) {
- if (!fMonitorJob.fExited) {
- fMonitorJob.kill();
- }
- requestMonitor.done();
- }
- }
-
protected class CommandMonitoringStep extends InitializationShutdownStep {
CommandMonitoringStep(Direction direction) { super(direction); }
@Override
protected void initialize(final RequestMonitor requestMonitor) {
- startCommandProcessing(fProcess.getInputStream(), fProcess.getOutputStream());
+ startCommandProcessing(fMIBackend.getMIInputStream(), fMIBackend.getMIOutputStream());
requestMonitor.done();
}
@@ -693,7 +463,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
@Override
public void initialize(final RequestMonitor requestMonitor) {
try {
- fCLIProcess = new GDBCLIProcess(GDBControl_7_0.this);
+ fCLIProcess = new MIBackendCLIProcess(GDBControl_7_0.this, fMIBackend);
}
catch(IOException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Failed to create CLI Process", e)); //$NON-NLS-1$
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBInferiorProcess.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBInferiorProcess.java
index 1243f70278c..d574a783905 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBInferiorProcess.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBInferiorProcess.java
@@ -18,6 +18,7 @@ import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
import org.eclipse.dd.dsf.debug.service.command.ICommandControlService;
+import org.eclipse.dd.gdb.internal.provisional.service.IGDBBackend;
import org.eclipse.dd.mi.service.command.MIInferiorProcess;
/**
@@ -25,13 +26,16 @@ import org.eclipse.dd.mi.service.command.MIInferiorProcess;
*/
class GDBInferiorProcess extends MIInferiorProcess {
+ private IGDBBackend fBackend;
- public GDBInferiorProcess(ICommandControlService commandControl, PTY p) {
+ public GDBInferiorProcess(ICommandControlService commandControl, IGDBBackend backend, PTY p) {
super(commandControl, p);
+ fBackend = backend;
}
- public GDBInferiorProcess(ICommandControlService commandControl, OutputStream gdbOutputStream) {
+ public GDBInferiorProcess(ICommandControlService commandControl, IGDBBackend backend, OutputStream gdbOutputStream) {
super(commandControl, gdbOutputStream);
+ fBackend = backend;
}
@Override
@@ -54,7 +58,7 @@ class GDBInferiorProcess extends MIInferiorProcess {
if (gdb.getIsAttachSession() == false) {
// Try to interrupt the inferior, first.
if (getState() == State.RUNNING) {
- gdb.interrupt();
+ fBackend.interrupt();
}
}
}
diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/IGDBControl.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/IGDBControl.java
index a0434116746..19f7902d21c 100644
--- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/IGDBControl.java
+++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/IGDBControl.java
@@ -23,11 +23,6 @@ public interface IGDBControl extends ICommandControlService {
SessionType getSessionType();
boolean getIsAttachSession();
- boolean canInterrupt();
-
- void interrupt();
-
- void destroy();
void terminate(final RequestMonitor rm);
void initInferiorInputOutput(final RequestMonitor requestMonitor);
@@ -41,15 +36,9 @@ public interface IGDBControl extends ICommandControlService {
void setConnected(boolean connected);
- Process getGDBProcess();
-
AbstractCLIProcess getCLIProcess();
MIInferiorProcess getInferiorProcess();
- boolean isGDBExited();
-
- int getGDBExitCode();
-
IPath getExecutablePath();
}
\ No newline at end of file
diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIBackend.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIBackend.java
new file mode 100644
index 00000000000..327296297fa
--- /dev/null
+++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIBackend.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * Nokia - create and use backend service.
+ *******************************************************************************/
+package org.eclipse.dd.mi.service;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.dd.dsf.concurrent.Immutable;
+import org.eclipse.dd.dsf.service.IDsfService;
+
+/**
+ * Service for controlling the back end process.
+ * @since 1.1
+ */
+public interface IMIBackend extends IDsfService {
+
+ public enum State { NOT_INITIALIZED, STARTED, TERMINATED };
+
+ /**
+ * Event indicating that the back end process has started.
+ */
+ @Immutable
+ public static class BackendStateChangedEvent {
+ final private String fSessionId;
+ final private String fBackendId;
+ final private State fState;
+
+ public BackendStateChangedEvent(String sessionId, String backendId, State state) {
+ fSessionId = sessionId;
+ fBackendId = backendId;
+ fState = state;
+ }
+
+ public String getSessionId() {
+ return fSessionId;
+ }
+
+ public String getBackendId() {
+ return fBackendId;
+ }
+
+ public State getState() {
+ return fState;
+ }
+ }
+
+ /**
+ * Returns the identifier of this backend service. It can be used
+ * to distinguish between multiple instances of this service in a
+ * single session.
+ */
+ public String getId();
+
+ /**
+ * Requests that the backend be immediately terminated.
+ */
+ public void destroy();
+
+ /**
+ * Returns the current state of the backed.
+ * @return
+ */
+ public State getState();
+
+ /**
+ * Returns the exit code of the backend. Returns 0
if
+ * the backend exit code is not available.
+ * @return
+ */
+ public int getExitCode();
+
+ /**
+ * Returns the backend command stream.
+ */
+ public InputStream getMIInputStream();
+
+ /**
+ * Returns the backend result and event stream.
+ * @return
+ */
+ public OutputStream getMIOutputStream();
+}
diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java
index 45ddd553f9a..a385775d9ed 100644
--- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java
+++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java
@@ -8,6 +8,7 @@
* Contributors:
* Wind River Systems - initial API and implementation
* Ericsson - Modified for handling of multiple stacks and threads
+ * Nokia - create and use backend service.
*******************************************************************************/
package org.eclipse.dd.mi.service.command;
@@ -109,21 +110,17 @@ public abstract class AbstractMIControl extends AbstractDsfService
* Flag indicating that the command control has stopped processing commands.
*/
private boolean fStoppedCommandProcessing = false;
-
- private String fId;
public AbstractMIControl(DsfSession session) {
super(session);
- fId = ""; //$NON-NLS-1$
fUseThreadAndFrameOptions = false;
}
/**
* @since 1.1
*/
- public AbstractMIControl(DsfSession session, String id, boolean useThreadAndFrameOptions) {
+ public AbstractMIControl(DsfSession session, boolean useThreadAndFrameOptions) {
super(session);
- fId = id;
fUseThreadAndFrameOptions = useThreadAndFrameOptions;
}
@@ -369,13 +366,6 @@ public abstract class AbstractMIControl extends AbstractDsfService
return !fStoppedCommandProcessing;
}
- /**
- * @since 1.1
- */
- public String getId() {
- return fId;
- }
-
/*
* These are the service routines which perform the various callouts back to the listeners.
*/
diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIBackendCLIProcess.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIBackendCLIProcess.java
new file mode 100644
index 00000000000..464850586f3
--- /dev/null
+++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIBackendCLIProcess.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.mi.service.command;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.dd.dsf.concurrent.DsfRunnable;
+import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.dd.dsf.concurrent.Query;
+import org.eclipse.dd.dsf.concurrent.RequestMonitor;
+import org.eclipse.dd.dsf.debug.service.command.ICommandControlService;
+import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.mi.internal.MIPlugin;
+import org.eclipse.dd.mi.service.IMIBackend;
+import org.eclipse.dd.mi.service.IMIBackend.BackendStateChangedEvent;
+
+/**
+ * CLI Process object implementation which uses the {@link IMIBackend} service
+ * to monitor and control the underlying process.
+ *
+ * @since 1.1
+ */
+public class MIBackendCLIProcess extends AbstractCLIProcess {
+
+ private IMIBackend fMIBackend;
+ private AtomicInteger fExitCode = new AtomicInteger(-1);
+ private BackedExitedEventListener fExitedEventListener;
+
+ @ConfinedToDsfExecutor("getSession()#getExecutor")
+ public MIBackendCLIProcess(ICommandControlService commandControl, IMIBackend backend) throws IOException {
+ super(commandControl);
+ fMIBackend = backend;
+ if (fMIBackend.getState() == IMIBackend.State.TERMINATED) {
+ fExitCode.set(fMIBackend.getExitCode());
+ }
+ fExitedEventListener = new BackedExitedEventListener();
+ getSession().addServiceEventListener(fExitedEventListener, null);
+ }
+
+ public class BackedExitedEventListener {
+ private final List fWaitForRMs = new ArrayList();
+
+ @DsfServiceEventHandler
+ public void eventDispatched(BackendStateChangedEvent event) {
+ if (event.getState() == IMIBackend.State.TERMINATED &&
+ event.getBackendId().equals(fMIBackend.getId()))
+ {
+ fExitCode.set(fMIBackend.getExitCode());
+ for (RequestMonitor rm : fWaitForRMs) {
+ rm.done();
+ }
+ fWaitForRMs.clear();
+ }
+ }
+
+ void dispose() {
+ for (RequestMonitor rm : fWaitForRMs) {
+ rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Backend terminate event never received", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ fWaitForRMs.clear();
+ }
+ }
+
+ /**
+ * @see java.lang.Process#waitFor()
+ */
+ @Override
+ public int waitFor() throws InterruptedException {
+ if (!DsfSession.isSessionActive(getSession().getId())) {
+ return fExitCode.get();
+ }
+
+ try {
+ Query query = new Query() {
+ @Override
+ protected void execute(final DataRequestMonitor rm) {
+ if ( !DsfSession.isSessionActive(getSession().getId()) ||
+ isDisposed() ||
+ fMIBackend.getState() == IMIBackend.State.TERMINATED )
+ {
+ rm.setData(new Object());
+ rm.done();
+ } else {
+ fExitedEventListener.fWaitForRMs.add(
+ new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(new Object());
+ rm.done();
+ }
+ });
+ }
+ }
+ };
+ getSession().getExecutor().execute(query);
+ query.get();
+ } catch (RejectedExecutionException e) {
+ } catch (ExecutionException e) {
+ }
+ return fExitCode.get();
+ }
+
+
+ /**
+ * @see java.lang.Process#exitValue()
+ */
+ @Override
+ public int exitValue() {
+ if (!DsfSession.isSessionActive(getSession().getId())) {
+ return fExitCode.get();
+ }
+ try {
+ getSession().getExecutor().submit(new Callable() {
+ public Object call() throws Exception {
+ if (fMIBackend.getState() != IMIBackend.State.TERMINATED) {
+ throw new IllegalThreadStateException("Backend Process has not exited"); //$NON-NLS-1$
+ }
+ return null;
+ }}).get();
+ } catch (RejectedExecutionException e) {
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException)e.getCause();
+ }
+ }
+ return fExitCode.get();
+ }
+ /**
+ * @see java.lang.Process#destroy()
+ */
+ @Override
+ public void destroy() {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() { public void run() {
+ if (!DsfSession.isSessionActive(getSession().getId())) return;
+ if (isDisposed()) return;
+
+ fMIBackend.destroy();
+ }});
+ } catch (RejectedExecutionException e) {
+ // Session disposed.
+ }
+ }
+
+ @Override
+ public void dispose() {
+ fExitedEventListener.dispose();
+ getSession().removeServiceEventListener(fExitedEventListener);
+ super.dispose();
+ }
+}
diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakList.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakList.java
index b3472ca9f50..ab3f2a0f84f 100644
--- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakList.java
+++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakList.java
@@ -26,7 +26,7 @@ import org.eclipse.dd.mi.service.command.output.MIOutput;
* `Number'
* number of the breakpoint
*
- * `Type'
+ * `State'
* type of the breakpoint: `breakpoint' or `watchpoint'
*
* `Disposition'
diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakListInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakListInfo.java
index 23de9da1edf..f00bafa8cae 100644
--- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakListInfo.java
+++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakListInfo.java
@@ -21,7 +21,7 @@ import java.util.List;
*
* ^done,BreakpointTable={nr_rows="1",nr_cols="6",hdr=[..],body=[brkpt={},brkpt={}]}
*-break-list
-^done,BreakpointTable={nr_rows="6",nr_cols="6",hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},{width="14",alignment="-1",col_name="type",colhdr="Type"},{width="4",alignment="-1",col_name="disp",colhdr="Disp"},{width="3",alignment="-1",col_name="enabled",colhdr="Enb"},{width="10",alignment="-1",col_name="addr",colhdr="Address"},{width="40",alignment="2",col_name="what",colhdr="What"}],body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="2",type="breakpoint",disp="del",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="3",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",cond="1",times="0"},bkpt={number="4",type="hw breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="5",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",thread="0",thread="0",times="0"},bkpt={number="6",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",thread="1",thread="1",times="0"}]}
+^done,BreakpointTable={nr_rows="6",nr_cols="6",hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},{width="14",alignment="-1",col_name="type",colhdr="State"},{width="4",alignment="-1",col_name="disp",colhdr="Disp"},{width="3",alignment="-1",col_name="enabled",colhdr="Enb"},{width="10",alignment="-1",col_name="addr",colhdr="Address"},{width="40",alignment="2",col_name="what",colhdr="What"}],body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="2",type="breakpoint",disp="del",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="3",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",cond="1",times="0"},bkpt={number="4",type="hw breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="5",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",thread="0",thread="0",times="0"},bkpt={number="6",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",thread="1",thread="1",times="0"}]}
*
*/
public class MIBreakListInfo extends MIInfo {