blob: b896dd5ce7ea2a64ebf26730c0884923ac652107 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2011 Wind River Systems 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:
* 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<>();
@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();
}
}