/******************************************************************************* * Copyright (c) 2015 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: * 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; } } } } } }