/******************************************************************************* * Copyright (c) 2007, 2011 Wind River Systems 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service.command; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Query; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.mi.service.IMIBackend; import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent; 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; /** * CLI Process object implementation which uses the {@link IMIBackend} service * to monitor and control the underlying process. * * Note that starting with GDB 7.12, as long as a PTY is available, * this process is no longer used. Instead, the real GDB process, * along with its console will be used directly. A second PTY * will be used to communicate using MI. * * @since 1.1 */ public class MIBackendCLIProcess extends AbstractCLIProcess { private IMIBackend fMIBackend; private AtomicInteger fExitCode = new AtomicInteger(-1); private BackedExitedEventListener fExitedEventListener; @ConfinedToDsfExecutor("getSession()#getExecutor") public MIBackendCLIProcess(ICommandControlService commandControl, IMIBackend backend) throws IOException { super(commandControl); fMIBackend = backend; if (fMIBackend.getState() == IMIBackend.State.TERMINATED) { fExitCode.set(fMIBackend.getExitCode()); } fExitedEventListener = new BackedExitedEventListener(); getSession().addServiceEventListener(fExitedEventListener, null); } public class BackedExitedEventListener { private final List<RequestMonitor> fWaitForRMs = new ArrayList<RequestMonitor>(); @DsfServiceEventHandler public void eventDispatched(BackendStateChangedEvent event) { if (event.getState() == IMIBackend.State.TERMINATED && event.getBackendId().equals(fMIBackend.getId())) { fExitCode.set(fMIBackend.getExitCode()); for (RequestMonitor rm : fWaitForRMs) { rm.done(); } fWaitForRMs.clear(); } } void dispose() { for (RequestMonitor rm : fWaitForRMs) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Backend terminate event never received", null)); //$NON-NLS-1$ rm.done(); } fWaitForRMs.clear(); } } /** * @see java.lang.Process#waitFor() */ @Override public int waitFor() throws InterruptedException { if (!DsfSession.isSessionActive(getSession().getId())) { return fExitCode.get(); } try { Query<Object> query = new Query<Object>() { @Override protected void execute(final DataRequestMonitor<Object> rm) { if ( !DsfSession.isSessionActive(getSession().getId()) || isDisposed() || fMIBackend.getState() == IMIBackend.State.TERMINATED ) { rm.setData(new Object()); rm.done(); } else { fExitedEventListener.fWaitForRMs.add( new ImmediateRequestMonitor(rm) { @Override protected void handleSuccess() { rm.setData(new Object()); rm.done(); } }); } } }; getSession().getExecutor().execute(query); query.get(); } catch (RejectedExecutionException e) { } catch (ExecutionException e) { } return fExitCode.get(); } /** * @see java.lang.Process#exitValue() */ @Override public int exitValue() { if (!DsfSession.isSessionActive(getSession().getId())) { return fExitCode.get(); } try { getSession().getExecutor().submit(new Callable<Object>() { @Override public Object call() throws Exception { if (fMIBackend.getState() != IMIBackend.State.TERMINATED) { throw new IllegalThreadStateException("Backend Process has not exited"); //$NON-NLS-1$ } return null; }}).get(); } catch (RejectedExecutionException e) { } catch (InterruptedException e) { } catch (ExecutionException e) { if (e.getCause() instanceof RuntimeException) { throw (RuntimeException)e.getCause(); } } return fExitCode.get(); } /** * @see java.lang.Process#destroy() */ @Override public void destroy() { try { getSession().getExecutor().execute(new DsfRunnable() { @Override public void run() { if (!DsfSession.isSessionActive(getSession().getId())) return; if (isDisposed()) return; fMIBackend.destroy(); }}); } catch (RejectedExecutionException e) { // Session disposed. } } @Override public void dispose() { fExitedEventListener.dispose(); getSession().removeServiceEventListener(fExitedEventListener); super.dispose(); } }