From d8e9fa07820db1169025a3dadab406a60032c1f2 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Wed, 20 May 2009 13:45:58 +0000 Subject: [PATCH] [234467] When terminating a DSF-GDB launch, interrupt the inferior if it is running. Without that, the inferior is left running even though GDB is killed. --- .../service/command/GDBBackendCLIProcess.java | 60 +++++++++++++++++++ .../dsf/gdb/service/command/GDBControl.java | 25 +++++--- .../gdb/service/command/GDBControl_7_0.java | 25 +++++--- 3 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBBackendCLIProcess.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBBackendCLIProcess.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBBackendCLIProcess.java new file mode 100644 index 00000000000..25c65bc6717 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBBackendCLIProcess.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2009 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: + * Nokia - initial version. May 5, 2009 + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.service.command; + + +import java.io.IOException; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.mi.service.IMIBackend; +import org.eclipse.cdt.dsf.mi.service.command.MIBackendCLIProcess; +import org.eclipse.cdt.dsf.service.DsfSession; + +/** + * @author LWang + * @since 2.0 + * + */ +public class GDBBackendCLIProcess extends MIBackendCLIProcess { + + /** + * @param commandControl + * @param backend + * @throws IOException + */ + public GDBBackendCLIProcess(ICommandControlService commandControl, + IMIBackend backend) throws IOException { + super(commandControl, backend); + assert(commandControl instanceof IGDBControl); + } + + @Override + public void destroy() { + try { + // This is called when user terminate the "launch" or "gdb" process + // in Debug View. We need to kill inferior too. Fix bug + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=234467 + // + getSession().getExecutor().execute(new DsfRunnable() { public void run() { + if (!DsfSession.isSessionActive(getSession().getId())) return; + if (isDisposed()) return; + + ((IGDBControl)getCommandControlService()).terminate( + new RequestMonitor(getSession().getExecutor(), null)); + }}); + } catch (RejectedExecutionException e) { + // Session disposed. + } + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java index 39763536a69..005bf5983fd 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java @@ -41,10 +41,10 @@ import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerStartedDMEvent; import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess; import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl; import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor; -import org.eclipse.cdt.dsf.mi.service.command.MIBackendCLIProcess; import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess; import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor; +import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess.State; import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakInsert; import org.eclipse.cdt.dsf.mi.service.command.commands.MICommand; import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue; @@ -177,10 +177,18 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { } public void terminate(final RequestMonitor rm) { + // To fix bug 234467: + // Interrupt GDB in case the inferior is running. + // That way, the inferior will also be killed when we exit GDB. + // + if (fInferiorProcess.getState() == State.RUNNING) { + fMIBackend.interrupt(); + } + // Schedule a runnable to be executed 2 seconds from now. // If we don't get a response to the quit command, this // runnable will kill the task. - final Future quitTimeoutFuture = getExecutor().schedule( + final Future forceQuitTask = getExecutor().schedule( new DsfRunnable() { public void run() { fMIBackend.destroy(); @@ -199,13 +207,14 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { 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()) { - fMIBackend.destroy(); - } + if (isSuccess()) { + // Cancel the time out runnable (if it hasn't run yet). + forceQuitTask.cancel(false); rm.done(); } + // else: the forceQuitTask has or will handle it. + // It is good to wait for the forceQuitTask to trigger + // to leave enough time for the interrupt() to complete. } } ); @@ -463,7 +472,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { @Override public void initialize(final RequestMonitor requestMonitor) { try { - fCLIProcess = new MIBackendCLIProcess(GDBControl.this, fMIBackend); + fCLIProcess = new GDBBackendCLIProcess(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/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java index a8c78987f72..83170ec69c4 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java @@ -43,10 +43,10 @@ import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent; import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess; import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl; import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor_7_0; -import org.eclipse.cdt.dsf.mi.service.command.MIBackendCLIProcess; import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess; import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor_7_0; +import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess.State; import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakInsert; import org.eclipse.cdt.dsf.mi.service.command.commands.MICommand; import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue; @@ -178,10 +178,18 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl { } public void terminate(final RequestMonitor rm) { + // To fix bug 234467: + // Interrupt GDB in case the inferior is running. + // That way, the inferior will also be killed when we exit GDB. + // + if (fInferiorProcess.getState() == State.RUNNING) { + fMIBackend.interrupt(); + } + // Schedule a runnable to be executed 2 seconds from now. // If we don't get a response to the quit command, this // runnable will kill the task. - final Future quitTimeoutFuture = getExecutor().schedule( + final Future forceQuitTask = getExecutor().schedule( new DsfRunnable() { public void run() { fMIBackend.destroy(); @@ -200,13 +208,14 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl { 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()) { - fMIBackend.destroy(); - } + if (isSuccess()) { + // Cancel the time out runnable (if it hasn't run yet). + forceQuitTask.cancel(false); rm.done(); } + // else: the forceQuitTask has or will handle it. + // It is good to wait for the forceQuitTask to trigger + // to leave enough time for the interrupt() to complete. } } ); @@ -601,7 +610,7 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl { @Override public void initialize(final RequestMonitor requestMonitor) { try { - fCLIProcess = new MIBackendCLIProcess(GDBControl_7_0.this, fMIBackend); + fCLIProcess = new GDBBackendCLIProcess(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$