/*******************************************************************************
* Copyright (c) 2011 Ericsson and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ericsson - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
import java.util.Hashtable;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
/**
* Version of the non-stop runControl for GDB 7.2.
*
* @since 4.0
*/
public class GDBRunControl_7_2_NS extends GDBRunControl_7_0_NS
{
private ICommandControlService fConnection;
private CommandFactory fCommandFactory;
/**
* Keeps track if we are currently visualizing trace data or not
*/
private boolean fTraceVisualization;
///////////////////////////////////////////////////////////////////////////
// Initialization and shutdown
///////////////////////////////////////////////////////////////////////////
public GDBRunControl_7_2_NS(DsfSession session) {
super(session);
}
@Override
public void initialize(final RequestMonitor rm) {
super.initialize(new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
doInitialize(rm);
}
});
}
private void doInitialize(final RequestMonitor rm) {
register(new String[]{ IRunControl.class.getName(),
IRunControl2.class.getName(),
IMIRunControl.class.getName(),
GDBRunControl_7_0_NS.class.getName(),
GDBRunControl_7_2_NS.class.getName(),
},
new Hashtable<String,String>());
fConnection = getServicesTracker().getService(ICommandControlService.class);
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
getSession().addServiceEventListener(this, null);
rm.done();
}
@Override
public void shutdown(final RequestMonitor rm) {
unregister();
getSession().removeServiceEventListener(this);
super.shutdown(rm);
}
/** @since 4.1 */
protected boolean getTraceVisualization() {
return fTraceVisualization;
}
/** @since 4.1 */
protected void setTraceVisualization(boolean visualizing) {
fTraceVisualization = visualizing;
}
// Now that the flag --thread-group is globally supported
// by GDB 7.2, we have to make sure not to use it twice.
// Bug 340262
@Override
public void suspend(final IExecutionDMContext context, final RequestMonitor rm) {
assert context != null;
IMIExecutionDMContext thread = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
IMIContainerDMContext container = DMContexts.getAncestorOfType(context, IMIContainerDMContext.class);
if (thread == null && container == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Invalid context type.", null)); //$NON-NLS-1$
rm.done();
return;
}
canSuspend(context, new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
if (getData()) {
fConnection.queueCommand(fCommandFactory.createMIExecInterrupt(context), new DataRequestMonitor<MIInfo>(getExecutor(), rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
"Given context: " + context + ", is already suspended.", null)); //$NON-NLS-1$ //$NON-NLS-2$
rm.done();
}
}
});
}
// Now that the flag --thread-group is globally supported
// by GDB 7.2, we have to make sure not to use it twice.
// Bug 340262
@Override
public void resume(final IExecutionDMContext context, final RequestMonitor rm) {
assert context != null;
final IMIExecutionDMContext thread = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
final IMIContainerDMContext container = DMContexts.getAncestorOfType(context, IMIContainerDMContext.class);
if (thread == null && container == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Invalid context type.", null)); //$NON-NLS-1$
rm.done();
return;
}
canResume(context, new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
if (getData()) {
if (thread != null) {
doResumeThread(thread, rm);
return;
}
if (container != null) {
doResumeContainer(container, rm);
return;
}
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
"Given context: " + context + ", is already running.", null)); //$NON-NLS-1$ //$NON-NLS-2$
rm.done();
}
}
});
}
private void doResumeThread(IMIExecutionDMContext context, final RequestMonitor rm) {
final MIThreadRunState threadState = fThreadRunStates.get(context);
if (threadState == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE,
"Given context: " + context + " can't be found.", null)); //$NON-NLS-1$ //$NON-NLS-2$
rm.done();
return;
}
threadState.fResumePending = true;
fConnection.queueCommand(fCommandFactory.createMIExecContinue(context), new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleFailure() {
threadState.fResumePending = false;
super.handleFailure();
}
});
}
private void doResumeContainer(IMIContainerDMContext context, final RequestMonitor rm) {
fConnection.queueCommand(fCommandFactory.createMIExecContinue(context), new DataRequestMonitor<MIInfo>(getExecutor(), rm));
}
/**
* @since 4.1
*/
@Override
@DsfServiceEventHandler
public void eventDispatched(ITraceRecordSelectedChangedDMEvent e) {
setTraceVisualization(e.isVisualizationModeEnabled());
// Disable or re-enable run control operations if we are looking
// at trace data or we are not, respectively.
setRunControlOperationsEnabled(!e.isVisualizationModeEnabled());
}
@Override
protected void refreshThreadStates() {
// We should not refresh the thread state while we are visualizing trace data.
// This is because GDB will report the state of the threads of the executing
// program, while we should only deal with a 'fake' stopped thread 1, during
// visualization.
// So, simply keep the state of the threads as is until visualization stops.
// Bug 347514
if (getTraceVisualization() == false) {
super.refreshThreadStates();
}
}
}