/******************************************************************************* * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * 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 *******************************************************************************/ package gov.redhawk.ide.debug.linux; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ProcessTree { private Map<String, List<String>> processTree = new HashMap<String, List<String>>(); private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s+(\\d+)"); private static final int MAX_ATTEMPTS = 2; public ProcessTree() throws IOException { createProcessList(); } private void createProcessList() throws IOException { ProcessBuilder builder = new ProcessBuilder("/bin/ps", "-eo", "pid,ppid"); builder.redirectErrorStream(true); Process process = builder.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String firstLine = reader.readLine(); if (!" PID PPID".equals(firstLine)) { throw new IOException("Unexpected result"); } for (String line = reader.readLine(); line != null; line = reader.readLine()) { Matcher matcher = PATTERN.matcher(line); if (matcher.matches()) { String ppid = matcher.group(2); String pid = matcher.group(1); List<String> list = processTree.get(ppid); if (list == null) { list = new ArrayList<String>(); processTree.put(ppid, list); } list.add(pid); } } } private List<String> getChildren(String pid) { List<String> children = processTree.get(pid); if (children == null || children.isEmpty()) { return Collections.singletonList(pid); } else { List<String> retVal = new ArrayList<String>(); for (String childPid : children) { retVal.addAll(getChildren(childPid)); } retVal.addAll(children); retVal.add(pid); return retVal; } } private void kill(String pid) throws IOException { if (!isRunning(pid)) { return; } ProcessBuilder builder = new ProcessBuilder("kill", "-s", "SIGTERM", pid); Process p = builder.start(); try { p.waitFor(); if (p.exitValue() != 0) { return; } } catch (InterruptedException e) { // PASS } for (int attempts = 0; attempts < MAX_ATTEMPTS; attempts++) { if (isRunning(pid)) { try { Thread.sleep(250); } catch (InterruptedException e) { // PASS } } else { return; } } builder = new ProcessBuilder("kill", "-s", "SIGQUIT", pid); p = builder.start(); try { p.waitFor(); } catch (InterruptedException e) { // PASS } for (int attempts = 0; attempts < MAX_ATTEMPTS; attempts++) { if (isRunning(pid)) { try { Thread.sleep(250); } catch (InterruptedException e) { // PASS } } else { return; } } builder = new ProcessBuilder("kill", "-s", "SIGINT", pid); p = builder.start(); try { p.waitFor(); } catch (InterruptedException e) { // PASS } for (int attempts = 0; attempts < MAX_ATTEMPTS; attempts++) { if (isRunning(pid)) { try { Thread.sleep(250); } catch (InterruptedException e) { // PASS } } else { return; } } // Send SigKill to Destroy the process builder = new ProcessBuilder("kill", "-s", "SIGKILL", pid); p = builder.start(); try { p.waitFor(); } catch (InterruptedException e) { // PASS } } /** * @since 2.0 */ public void killAll(String ppid) throws IOException { List<String> children = getChildren(ppid); Collections.reverse(children); for (final String pid : children) { kill(pid); } } private boolean isRunning(String child) { File childDesc = new File("/proc/" + child); return childDesc.exists(); } }