| /* | |
| * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| import java.io.IOException; | |
| import java.lang.management.ManagementFactory; | |
| import java.time.Duration; | |
| import java.util.List; | |
| import java.util.stream.Collectors; | |
| import java.util.stream.Stream; | |
| import com.sun.management.OperatingSystemMXBean; | |
| import jdk.test.lib.Platform; | |
| /** | |
| * Useful utilities for testing Process and ProcessHandle. | |
| */ | |
| public abstract class ProcessUtil { | |
| /** | |
| * Constructor | |
| */ | |
| public ProcessUtil() {} | |
| /** | |
| * Returns the list of direct children. | |
| * WIndows conhost.exe children are filtered out. | |
| * @param ph the Process to get children of | |
| * @return a list of child ProcessHandles | |
| */ | |
| public static List<ProcessHandle> getChildren(ProcessHandle ph) { | |
| return ph.children() | |
| .filter(ProcessUtil::isNotWindowsConsole) | |
| .collect(Collectors.toList()); | |
| } | |
| /** | |
| * Returns the list of all direct and indirect children. | |
| * WIndows conhost.exe children are filtered out. | |
| * @param ph the Process to get children of | |
| * @return a list of child ProcessHandles | |
| */ | |
| public static List<ProcessHandle> getDescendants(ProcessHandle ph) { | |
| return ph.descendants() | |
| .filter(ProcessUtil::isNotWindowsConsole) | |
| .collect(Collectors.toList()); | |
| } | |
| /** | |
| * Waits for and returns the direct expected Children of a ProcessHandle. | |
| * For Windows, the conhost.exe children are filtered out. | |
| * | |
| * @param ph the process to get the children of | |
| * @param nchildren the minimum number of children to expect | |
| * @return a list of ProcessHandles of the children. | |
| */ | |
| public static List<ProcessHandle> waitForChildren(ProcessHandle ph, long nchildren) { | |
| List<ProcessHandle> subprocesses = null; | |
| long count = 0; | |
| do { | |
| if (subprocesses != null) { | |
| // Only wait if this is not the first time looking | |
| try { | |
| Thread.sleep(500L); // It will happen but don't burn the cpu | |
| } catch (InterruptedException ie) { | |
| // ignore | |
| } | |
| } | |
| subprocesses = getChildren(ph); | |
| count = subprocesses.size(); | |
| System.out.printf(" waiting for subprocesses of %s to start," + | |
| " expected: %d, current: %d%n", ph, nchildren, count); | |
| } while (count < nchildren); | |
| return subprocesses; | |
| } | |
| /** | |
| * Waits for and returns all expected Children of a ProcessHandle. | |
| * For Windows, the conhost.exe children are filtered out. | |
| * | |
| * @param ph the process to get the children of | |
| * @param nchildren the minimum number of children to expect | |
| * @return a list of ProcessHandles of the children. | |
| */ | |
| public static List<ProcessHandle> waitForAllChildren(ProcessHandle ph, long nchildren) { | |
| List<ProcessHandle> subprocesses = null; | |
| long count = 0; | |
| do { | |
| if (subprocesses != null) { | |
| // Only wait if this is not the first time looking | |
| try { | |
| Thread.sleep(500L); // It will happen but don't burn the cpu | |
| } catch (InterruptedException ie) { | |
| // ignore | |
| } | |
| } | |
| subprocesses = getDescendants(ph); | |
| count = subprocesses.size(); | |
| System.out.printf(" waiting for subprocesses of %s to start," + | |
| " expected: %d, current: %d%n", ph, nchildren, count); | |
| } while (count < nchildren); | |
| return subprocesses; | |
| } | |
| /** | |
| * Destroy all children of the ProcessHandle. | |
| * (Except the conhost.exe on Windows) | |
| * | |
| * @param p a ProcessHandle | |
| * @return the ProcessHandle | |
| */ | |
| public static ProcessHandle destroyProcessTree(ProcessHandle p) { | |
| Stream<ProcessHandle> children = p.descendants().filter(ProcessUtil::isNotWindowsConsole); | |
| children.forEach(ph -> { | |
| System.out.printf("destroyProcessTree destroyForcibly%n"); | |
| printProcess(ph); | |
| ph.destroyForcibly(); | |
| }); | |
| return p; | |
| } | |
| /** | |
| * The OSMXBean for this process. | |
| */ | |
| public static final OperatingSystemMXBean osMbean = | |
| (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); | |
| /** | |
| * Return the CPU time of the current process according to the OperatingSystemMXBean. | |
| * | |
| * @return the CPU time of the current process | |
| */ | |
| public static Duration MXBeanCpuTime() { | |
| return Duration.ofNanos(osMbean.getProcessCpuTime()); | |
| } | |
| /** | |
| * Return true if the ProcessHandle is a Windows i586 conhost.exe process. | |
| * | |
| * @param p the processHandle of the Process | |
| * @return Return true if the ProcessHandle is for a Windows i586 conhost.exe process | |
| */ | |
| static boolean isWindowsConsole(ProcessHandle p) { | |
| return Platform.isWindows() && p.info().command().orElse("").endsWith("C:\\Windows\\System32\\conhost.exe"); | |
| } | |
| /** | |
| * Return true if the ProcessHandle is NOT a Windows i586 conhost.exe process. | |
| * | |
| * @param p the processHandle of the Process | |
| * @return Return true if the ProcessHandle is NOT for a Windows i586 conhost.exe process | |
| */ | |
| static boolean isNotWindowsConsole(ProcessHandle p) { | |
| return !isWindowsConsole(p); | |
| } | |
| /** | |
| * Print a formatted string to System.out. | |
| * @param format the format | |
| * @param args the argument array | |
| */ | |
| static void printf(String format, Object... args) { | |
| String s = String.format(format, args); | |
| System.out.print(s); | |
| } | |
| /** | |
| * Print information about a process. | |
| * Prints the pid, if it is alive, and information about the process. | |
| * @param ph the processHandle at the top | |
| */ | |
| static void printProcess(ProcessHandle ph) { | |
| printProcess(ph, ""); | |
| } | |
| /** | |
| * Print information about a process. | |
| * Prints the pid, if it is alive, and information about the process. | |
| * @param ph the processHandle at the top | |
| * @param prefix the String to prefix the output with | |
| */ | |
| static void printProcess(ProcessHandle ph, String prefix) { | |
| printf("%spid %s, alive: %s; parent: %s, %s%n", prefix, | |
| ph.pid(), ph.isAlive(), ph.parent(), ph.info()); | |
| } | |
| /** | |
| * Print the process hierarchy as visible via ProcessHandle. | |
| * Prints the pid, if it is alive, and information about the process. | |
| * @param ph the processHandle at the top | |
| * @param prefix the String to prefix the output with | |
| */ | |
| static void printDeep(ProcessHandle ph, String prefix) { | |
| printProcess(ph, prefix); | |
| ph.children().forEach(p -> printDeep(p, prefix + " ")); | |
| } | |
| /** | |
| * Use the native command to list the active processes. | |
| */ | |
| static void logTaskList() { | |
| String[] windowsArglist = {"tasklist.exe", "/v"}; | |
| String[] unixArglist = {"ps", "-ef"}; | |
| String[] argList = null; | |
| if (Platform.isWindows()) { | |
| argList = windowsArglist; | |
| } else if (Platform.isLinux() || Platform.isOSX()) { | |
| argList = unixArglist; | |
| } else { | |
| return; | |
| } | |
| ProcessBuilder pb = new ProcessBuilder(argList); | |
| pb.inheritIO(); | |
| try { | |
| Process proc = pb.start(); | |
| proc.waitFor(); | |
| } catch (IOException | InterruptedException ex) { | |
| ex.printStackTrace(); | |
| } | |
| } | |
| } |