1/* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24import java.io.IOException; 25import java.lang.management.ManagementFactory; 26import java.time.Duration; 27import java.util.List; 28import java.util.stream.Collectors; 29import java.util.stream.Stream; 30 31import com.sun.management.OperatingSystemMXBean; 32import jdk.test.lib.Platform; 33 34/** 35 * Useful utilities for testing Process and ProcessHandle. 36 */ 37public abstract class ProcessUtil { 38 /** 39 * Constructor 40 */ 41 public ProcessUtil() {} 42 43 /** 44 * Returns the list of direct children. 45 * WIndows conhost.exe children are filtered out. 46 * @param ph the Process to get children of 47 * @return a list of child ProcessHandles 48 */ 49 public static List<ProcessHandle> getChildren(ProcessHandle ph) { 50 return ph.children() 51 .filter(ProcessUtil::isNotWindowsConsole) 52 .collect(Collectors.toList()); 53 } 54 55 /** 56 * Returns the list of all direct and indirect children. 57 * WIndows conhost.exe children are filtered out. 58 * @param ph the Process to get children of 59 * @return a list of child ProcessHandles 60 */ 61 public static List<ProcessHandle> getDescendants(ProcessHandle ph) { 62 return ph.descendants() 63 .filter(ProcessUtil::isNotWindowsConsole) 64 .collect(Collectors.toList()); 65 } 66 67 /** 68 * Waits for and returns the direct expected Children of a ProcessHandle. 69 * For Windows, the conhost.exe children are filtered out. 70 * 71 * @param ph the process to get the children of 72 * @param nchildren the minimum number of children to expect 73 * @return a list of ProcessHandles of the children. 74 */ 75 public static List<ProcessHandle> waitForChildren(ProcessHandle ph, long nchildren) { 76 List<ProcessHandle> subprocesses = null; 77 long count = 0; 78 do { 79 if (subprocesses != null) { 80 // Only wait if this is not the first time looking 81 try { 82 Thread.sleep(500L); // It will happen but don't burn the cpu 83 } catch (InterruptedException ie) { 84 // ignore 85 } 86 } 87 subprocesses = getChildren(ph); 88 count = subprocesses.size(); 89 System.out.printf(" waiting for subprocesses of %s to start," + 90 " expected: %d, current: %d%n", ph, nchildren, count); 91 } while (count < nchildren); 92 return subprocesses; 93 } 94 95 /** 96 * Waits for and returns all expected Children of a ProcessHandle. 97 * For Windows, the conhost.exe children are filtered out. 98 * 99 * @param ph the process to get the children of 100 * @param nchildren the minimum number of children to expect 101 * @return a list of ProcessHandles of the children. 102 */ 103 public static List<ProcessHandle> waitForAllChildren(ProcessHandle ph, long nchildren) { 104 List<ProcessHandle> subprocesses = null; 105 long count = 0; 106 do { 107 if (subprocesses != null) { 108 // Only wait if this is not the first time looking 109 try { 110 Thread.sleep(500L); // It will happen but don't burn the cpu 111 } catch (InterruptedException ie) { 112 // ignore 113 } 114 } 115 subprocesses = getDescendants(ph); 116 count = subprocesses.size(); 117 System.out.printf(" waiting for subprocesses of %s to start," + 118 " expected: %d, current: %d%n", ph, nchildren, count); 119 } while (count < nchildren); 120 return subprocesses; 121 } 122 123 /** 124 * Destroy all children of the ProcessHandle. 125 * (Except the conhost.exe on Windows) 126 * 127 * @param p a ProcessHandle 128 * @return the ProcessHandle 129 */ 130 public static ProcessHandle destroyProcessTree(ProcessHandle p) { 131 Stream<ProcessHandle> children = p.descendants().filter(ProcessUtil::isNotWindowsConsole); 132 children.forEach(ph -> { 133 System.out.printf("destroyProcessTree destroyForcibly%n"); 134 printProcess(ph); 135 ph.destroyForcibly(); 136 }); 137 return p; 138 } 139 140 /** 141 * The OSMXBean for this process. 142 */ 143 public static final OperatingSystemMXBean osMbean = 144 (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); 145 146 /** 147 * Return the CPU time of the current process according to the OperatingSystemMXBean. 148 * 149 * @return the CPU time of the current process 150 */ 151 public static Duration MXBeanCpuTime() { 152 return Duration.ofNanos(osMbean.getProcessCpuTime()); 153 } 154 155 /** 156 * Return true if the ProcessHandle is a Windows i586 conhost.exe process. 157 * 158 * @param p the processHandle of the Process 159 * @return Return true if the ProcessHandle is for a Windows i586 conhost.exe process 160 */ 161 static boolean isWindowsConsole(ProcessHandle p) { 162 return Platform.isWindows() && p.info().command().orElse("").endsWith("C:\\Windows\\System32\\conhost.exe"); 163 } 164 165 /** 166 * Return true if the ProcessHandle is NOT a Windows i586 conhost.exe process. 167 * 168 * @param p the processHandle of the Process 169 * @return Return true if the ProcessHandle is NOT for a Windows i586 conhost.exe process 170 */ 171 static boolean isNotWindowsConsole(ProcessHandle p) { 172 return !isWindowsConsole(p); 173 } 174 175 /** 176 * Print a formatted string to System.out. 177 * @param format the format 178 * @param args the argument array 179 */ 180 static void printf(String format, Object... args) { 181 String s = String.format(format, args); 182 System.out.print(s); 183 } 184 185 /** 186 * Print information about a process. 187 * Prints the pid, if it is alive, and information about the process. 188 * @param ph the processHandle at the top 189 */ 190 static void printProcess(ProcessHandle ph) { 191 printProcess(ph, ""); 192 } 193 194 /** 195 * Print information about a process. 196 * Prints the pid, if it is alive, and information about the process. 197 * @param ph the processHandle at the top 198 * @param prefix the String to prefix the output with 199 */ 200 static void printProcess(ProcessHandle ph, String prefix) { 201 printf("%spid %s, alive: %s; parent: %s, %s%n", prefix, 202 ph.pid(), ph.isAlive(), ph.parent(), ph.info()); 203 } 204 205 /** 206 * Print the process hierarchy as visible via ProcessHandle. 207 * Prints the pid, if it is alive, and information about the process. 208 * @param ph the processHandle at the top 209 * @param prefix the String to prefix the output with 210 */ 211 static void printDeep(ProcessHandle ph, String prefix) { 212 printProcess(ph, prefix); 213 ph.children().forEach(p -> printDeep(p, prefix + " ")); 214 } 215 216 /** 217 * Use the native command to list the active processes. 218 */ 219 static void logTaskList() { 220 String[] windowsArglist = {"tasklist.exe", "/v"}; 221 String[] unixArglist = {"ps", "-ef"}; 222 223 String[] argList = null; 224 if (Platform.isWindows()) { 225 argList = windowsArglist; 226 } else if (Platform.isLinux() || Platform.isOSX()) { 227 argList = unixArglist; 228 } else { 229 return; 230 } 231 232 ProcessBuilder pb = new ProcessBuilder(argList); 233 pb.inheritIO(); 234 try { 235 Process proc = pb.start(); 236 proc.waitFor(); 237 } catch (IOException | InterruptedException ex) { 238 ex.printStackTrace(); 239 } 240 } 241} 242