diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/processfactory/PyProcessFactory.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/processfactory/PyProcessFactory.java index 4610781..e08767f 100644 --- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/processfactory/PyProcessFactory.java +++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/processfactory/PyProcessFactory.java @@ -8,8 +8,6 @@ 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 org.jvnet.process_factory.AbstractProcess; -import org.jvnet.process_factory.ProcessFactory; import org.python.pydev.core.log.Log; import org.python.pydev.debug.ui.DebugPrefsPage; @@ -59,9 +57,9 @@ public class PyProcessFactory implements IProcessFactory { public void destroy() { if (DebugPrefsPage.getKillSubprocessesWhenTerminatingProcess()) { try { - AbstractProcess p = ProcessFactory.CreateProcess(process); - //I.e.: this is the real change in this wrapper: when killing a process, we'll kill the children - //processes too, not only the main process (i.e.: so that we don't have zombie processes alive for + UnixProcessKiller p = new UnixProcessKiller(process); + //I.e.: this is the real change in this wrapper: when killing a process, we'll kill the children + //processes too, not only the main process (i.e.: so that we don't have zombie processes alive for //Django, etc). p.killRecursively(); } catch (Exception e) { diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/processfactory/UnixProcessKiller.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/processfactory/UnixProcessKiller.java new file mode 100644 index 0000000..c8ec14f --- /dev/null +++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/processfactory/UnixProcessKiller.java @@ -0,0 +1,108 @@ +package org.python.pydev.debug.processfactory; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.util.LinkedHashSet; +import java.util.StringTokenizer; + +public class UnixProcessKiller { + private final int pid; + + private static class Output { + + public final String stdout; + public final String stderr; + + public Output(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + } + } + + public UnixProcessKiller(Process p) + throws Exception { + this.pid = getPid(p); + } + + private static int getPid(Process process) + throws Exception { + try { + Field f = process.getClass().getDeclaredField("pid"); + f.setAccessible(true); + return f.getInt(process); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void killRecursively() + throws IOException { + LinkedHashSet listed = new LinkedHashSet<>(); + killRecursively(pid, listed); + } + + private static void killRecursively(int pid, LinkedHashSet listed) + throws IOException { + listed.add(Integer.valueOf(pid)); + Runtime.getRuntime().exec(new String[] { + "kill", "-stop", Integer.toString(pid) + }, null, null); + Process createProcess = Runtime.getRuntime().exec(new String[] { + "pgrep", "-P", Integer.toString(pid) + }, null, null); + Output outputPGrep = getProcessOutput(createProcess); + if (outputPGrep.stderr != null && outputPGrep.stderr.length() > 0) { + throw new RuntimeException(outputPGrep.stderr); + } + Runtime.getRuntime().exec(new String[] { + "kill", "-KILL", Integer.toString(pid) + }, null, null); + String ids = outputPGrep.stdout; + StringTokenizer strTok = new StringTokenizer(ids); + do { + if (!strTok.hasMoreTokens()) { + break; + } + String nextToken = strTok.nextToken(); + int found = Integer.parseInt(nextToken); + if (!listed.contains(Integer.valueOf(found))) { + killRecursively(found, listed); + } + } while (true); + } + + private static Output getProcessOutput(Process process) + throws IOException { + try { + process.getOutputStream().close(); + } catch (IOException e2) { + } + InputStreamReader inputStream = new InputStreamReader(new BufferedInputStream(process.getInputStream())); + InputStreamReader errorStream = new InputStreamReader(new BufferedInputStream(process.getErrorStream())); + try { + process.waitFor(); + } catch (InterruptedException e1) { + } + try { + Object sync = new Object(); + synchronized (sync) { + sync.wait(10L); + } + } catch (Exception e) { + } + return new Output(readInputStream(inputStream), readInputStream(errorStream)); + } + + private static String readInputStream(InputStreamReader in) + throws IOException { + StringBuffer contents = new StringBuffer(); + char buf[] = new char[80]; + int c; + while ((c = in.read(buf)) != -1) { + contents.append(buf, 0, c); + } + return contents.toString(); + } +} diff --git a/plugins/org.python.pydev.debug/META-INF/MANIFEST.MF b/plugins/org.python.pydev.debug/META-INF/MANIFEST.MF index e4ea072..12fd1ce 100644 --- a/plugins/org.python.pydev.debug/META-INF/MANIFEST.MF +++ b/plugins/org.python.pydev.debug/META-INF/MANIFEST.MF @@ -3,8 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Pydev debug Bundle-SymbolicName: org.python.pydev.debug; singleton:=true Bundle-Version: 4.5.5.qualifier -Bundle-ClassPath: pydev-debug.jar, - libs/winp-1.19.jar +Bundle-ClassPath: pydev-debug.jar Bundle-Activator: org.python.pydev.debug.core.PydevDebugPlugin Bundle-Vendor: Aptana Bundle-Localization: plugin diff --git a/plugins/org.python.pydev.debug/build.properties b/plugins/org.python.pydev.debug/build.properties index 0704b04..bf249fa 100644 --- a/plugins/org.python.pydev.debug/build.properties +++ b/plugins/org.python.pydev.debug/build.properties @@ -1,5 +1,4 @@ bin.includes = plugin.xml,\ - libs/winp-1.19.jar,\ META-INF/,\ schema/,\ icons/,\