package com.aptana.ruby.debug.core.launching; import java.lang.reflect.Field; import java.util.Map; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.IProcessFactory; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.RuntimeProcess; import com.aptana.core.util.PlatformUtil; import com.aptana.ruby.debug.core.RubyDebugCorePlugin; /** * When terminating processes generated by this factory, on Mac/Unix we send a SIGINT to the process before doing our * normal termination. * * @author cwilliams */ public class InterruptingProcessFactory implements IProcessFactory { public static final String ID = "com.aptana.ruby.debug.core.interruptingProcessFactory"; //$NON-NLS-1$ @SuppressWarnings("rawtypes") public IProcess newProcess(ILaunch launch, Process process, String label, Map attributes) { return new RuntimeProcess(launch, process, label, attributes) { @Override public void terminate() throws DebugException { if (!Platform.getOS().equals(Platform.OS_WIN32)) { killProcess(); } super.terminate(); } private Integer grabPid() { // FIXME This only works on Unix/Mac Sun JDK and is a nasty hack to grab the underlying process' pid try { Process realProcess = getSystemProcess(); Field f = realProcess.getClass().getDeclaredField("pid"); //$NON-NLS-1$ f.setAccessible(true); return (Integer) f.get(realProcess); } catch (Exception e) { // ignore } return -1; } /** * Attempts to send a SIGINT to the underlying process. This is equivalent to Ctrl+C. * * @return */ private IStatus killProcess() { int pid = grabPid(); if (pid <= 0) { return new Status(IStatus.ERROR, RubyDebugCorePlugin.getPluginIdentifier(), Messages.InterruptingProcessFactory_UnableToGrabPIDMsg); } PlatformUtil.killProcess(pid, 2); // SIGINT = 2 return Status.OK_STATUS; } }; } }