blob: 6618cc043d03c1d470e53af615a36a6df2fe9e2d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Ericsson and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Marc Khouzam (Ericsson) - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command;
import java.io.OutputStream;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.gdb.IGdbDebugConstants;
import org.eclipse.cdt.dsf.gdb.launching.InferiorRuntimeProcess;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadGroupExitedEvent;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
/**
* Specialization for GDB >= 7.3.
*
* @since 4.7
*/
public class MIInferiorProcess_7_3 extends MIInferiorProcess {
private DsfSession fSession;
@ConfinedToDsfExecutor("fSession#getExecutor")
public MIInferiorProcess_7_3(IContainerDMContext container, OutputStream gdbOutputStream) {
this(container, gdbOutputStream, null);
}
@ConfinedToDsfExecutor("fSession#getExecutor")
public MIInferiorProcess_7_3(IContainerDMContext container, PTY p) {
this(container, null, p);
}
@ConfinedToDsfExecutor("fSession#getExecutor")
protected MIInferiorProcess_7_3(IContainerDMContext container, final OutputStream gdbOutputStream, PTY pty) {
super(container, gdbOutputStream, pty);
fSession = DsfSession.getSession(container.getSessionId());
}
@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
@Override
public int exitValue() {
assert !fSession.getExecutor().isInExecutorThread();
synchronized (this) {
if (fExitCode != null) {
return fExitCode;
}
}
if (!isTerminated()) {
// Throw an exception because the process is still running.
throw new IllegalThreadStateException();
}
return 0;
}
/** @since 4.2 */
@Override
@DsfServiceEventHandler
public void eventDispatched(MIThreadGroupExitedEvent e) {
if (getContainer() instanceof IMIContainerDMContext) {
if (((IMIContainerDMContext) getContainer()).getGroupId().equals(e.getGroupId())) {
// With recent changes, we notice a restart by the exited/started
// events, and only then create the new inferior; this means the new
// inferior will no longer receive the exited event for the old inferior.
// But it does not hurt to leave the below if check just in case.
assert isStarted() : "Exited event should only be received for a started inferior"; //$NON-NLS-1$
if (isStarted()) {
// Only handle this event if this process was already
// started. This is to protect ourselves in the case of
// a restart, where the new inferior is already created
// and gets the exited event for the old inferior.
String exitCode = e.getExitCode();
if (exitCode != null) {
setExitCodeAttribute();
try {
// Must use 'decode' since GDB returns an octal value
Integer decodedExitCode = Integer.decode(exitCode);
synchronized (this) {
fExitCode = decodedExitCode;
}
} catch (NumberFormatException exception) {
}
}
}
}
}
}
/**
* Set an attribute in the inferior process of the launch to indicate
* that the inferior has properly exited and its exit value can be used.
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
private void setExitCodeAttribute() {
// Update the console label to contain the exit code
ILaunch launch = (ILaunch) fSession.getModelAdapter(ILaunch.class);
IProcess[] launchProcesses = launch.getProcesses();
for (IProcess proc : launchProcesses) {
if (proc instanceof InferiorRuntimeProcess) {
String groupAttribute = proc.getAttribute(IGdbDebugConstants.INFERIOR_GROUPID_ATTR);
if (getContainer() instanceof IMIContainerDMContext) {
if (groupAttribute != null
&& groupAttribute.equals(((IMIContainerDMContext) getContainer()).getGroupId())) {
// Simply set the attribute that indicates the inferior has properly exited and its
// exit code can be used.
proc.setAttribute(IGdbDebugConstants.INFERIOR_EXITED_ATTR, ""); //$NON-NLS-1$
return;
}
}
}
}
}
}