mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-04 14:55:41 +02:00
[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.
This commit is contained in:
parent
e1218f9cbd
commit
d8e9fa0782
3 changed files with 94 additions and 16 deletions
|
@ -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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.AbstractCLIProcess;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl;
|
import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor;
|
import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.MIBackendCLIProcess;
|
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext;
|
import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
|
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor;
|
import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor;
|
||||||
|
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess.State;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakInsert;
|
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.MICommand;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue;
|
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) {
|
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.
|
// Schedule a runnable to be executed 2 seconds from now.
|
||||||
// If we don't get a response to the quit command, this
|
// If we don't get a response to the quit command, this
|
||||||
// runnable will kill the task.
|
// runnable will kill the task.
|
||||||
final Future<?> quitTimeoutFuture = getExecutor().schedule(
|
final Future<?> forceQuitTask = getExecutor().schedule(
|
||||||
new DsfRunnable() {
|
new DsfRunnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
fMIBackend.destroy();
|
fMIBackend.destroy();
|
||||||
|
@ -199,13 +207,14 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
|
||||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||||
@Override
|
@Override
|
||||||
public void handleCompleted() {
|
public void handleCompleted() {
|
||||||
// Cancel the time out runnable (if it hasn't run yet).
|
if (isSuccess()) {
|
||||||
if (quitTimeoutFuture.cancel(false)) {
|
// Cancel the time out runnable (if it hasn't run yet).
|
||||||
if (!isSuccess()) {
|
forceQuitTask.cancel(false);
|
||||||
fMIBackend.destroy();
|
|
||||||
}
|
|
||||||
rm.done();
|
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
|
@Override
|
||||||
public void initialize(final RequestMonitor requestMonitor) {
|
public void initialize(final RequestMonitor requestMonitor) {
|
||||||
try {
|
try {
|
||||||
fCLIProcess = new MIBackendCLIProcess(GDBControl.this, fMIBackend);
|
fCLIProcess = new GDBBackendCLIProcess(GDBControl.this, fMIBackend);
|
||||||
}
|
}
|
||||||
catch(IOException e) {
|
catch(IOException e) {
|
||||||
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Failed to create CLI Process", e)); //$NON-NLS-1$
|
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Failed to create CLI Process", e)); //$NON-NLS-1$
|
||||||
|
|
|
@ -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.AbstractCLIProcess;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl;
|
import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor_7_0;
|
import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor_7_0;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.MIBackendCLIProcess;
|
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext;
|
import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
|
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor_7_0;
|
import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor_7_0;
|
||||||
|
import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess.State;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIBreakInsert;
|
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.MICommand;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue;
|
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) {
|
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.
|
// Schedule a runnable to be executed 2 seconds from now.
|
||||||
// If we don't get a response to the quit command, this
|
// If we don't get a response to the quit command, this
|
||||||
// runnable will kill the task.
|
// runnable will kill the task.
|
||||||
final Future<?> quitTimeoutFuture = getExecutor().schedule(
|
final Future<?> forceQuitTask = getExecutor().schedule(
|
||||||
new DsfRunnable() {
|
new DsfRunnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
fMIBackend.destroy();
|
fMIBackend.destroy();
|
||||||
|
@ -200,13 +208,14 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
|
||||||
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
|
||||||
@Override
|
@Override
|
||||||
public void handleCompleted() {
|
public void handleCompleted() {
|
||||||
// Cancel the time out runnable (if it hasn't run yet).
|
if (isSuccess()) {
|
||||||
if (quitTimeoutFuture.cancel(false)) {
|
// Cancel the time out runnable (if it hasn't run yet).
|
||||||
if (!isSuccess()) {
|
forceQuitTask.cancel(false);
|
||||||
fMIBackend.destroy();
|
|
||||||
}
|
|
||||||
rm.done();
|
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
|
@Override
|
||||||
public void initialize(final RequestMonitor requestMonitor) {
|
public void initialize(final RequestMonitor requestMonitor) {
|
||||||
try {
|
try {
|
||||||
fCLIProcess = new MIBackendCLIProcess(GDBControl_7_0.this, fMIBackend);
|
fCLIProcess = new GDBBackendCLIProcess(GDBControl_7_0.this, fMIBackend);
|
||||||
}
|
}
|
||||||
catch(IOException e) {
|
catch(IOException e) {
|
||||||
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Failed to create CLI Process", e)); //$NON-NLS-1$
|
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Failed to create CLI Process", e)); //$NON-NLS-1$
|
||||||
|
|
Loading…
Add table
Reference in a new issue