1 /* 2 * Copyright (c) 2018, 2019, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.platform.cgroupv1; 27 28 import java.io.BufferedReader; 29 import java.io.IOException; 30 import java.math.BigInteger; 31 import java.nio.file.Files; 32 import java.nio.file.Paths; 33 import java.security.AccessController; 34 import java.security.PrivilegedActionException; 35 import java.security.PrivilegedExceptionAction; 36 import java.util.ArrayList; 37 import java.util.List; 38 import java.util.Optional; 39 import java.util.function.Function; 40 import java.util.stream.Stream; 41 42 public class SubSystem { 43 String root; 44 String mountPoint; 45 String path; 46 47 public SubSystem(String root, String mountPoint) { 48 this.root = root; 49 this.mountPoint = mountPoint; 50 } 51 52 public void setPath(String cgroupPath) { 53 if (root != null && cgroupPath != null) { 54 if (root.equals("/")) { 55 if (!cgroupPath.equals("/")) { 56 path = mountPoint + cgroupPath; 57 } 58 else { 59 path = mountPoint; 60 } 61 } 62 else { 63 if (root.equals(cgroupPath)) { 64 path = mountPoint; 65 } 66 else { 67 if (cgroupPath.startsWith(root)) { 68 if (cgroupPath.length() > root.length()) { 69 String cgroupSubstr = cgroupPath.substring(root.length()); 70 path = mountPoint + cgroupSubstr; 71 } 72 } 73 } 74 } 75 } 76 } 77 78 public String path() { 79 return path; 80 } 81 82 /** 83 * getSubSystemStringValue 84 * 85 * Return the first line of the file "parm" argument from the subsystem. 86 * 87 * TODO: Consider using weak references for caching BufferedReader object. 88 * 89 * @param subsystem 90 * @param parm 91 * @return Returns the contents of the file specified by param. 92 */ 93 public static String getStringValue(SubSystem subsystem, String parm) { 94 if (subsystem == null) return null; 95 96 try { 97 return subsystem.readStringValue(parm); 98 } catch (IOException e) { 99 return null; 100 } 101 } 102 103 private String readStringValue(String param) throws IOException { 104 PrivilegedExceptionAction<BufferedReader> pea = () -> 105 Files.newBufferedReader(Paths.get(path(), param)); 106 try (BufferedReader bufferedReader = 107 AccessController.doPrivileged(pea)) { 108 String line = bufferedReader.readLine(); 109 return line; 110 } catch (PrivilegedActionException e) { 111 Metrics.unwrapIOExceptionAndRethrow(e); 112 throw new InternalError(e.getCause()); 113 } 114 } 115 116 public static long getLongValueMatchingLine(SubSystem subsystem, 117 String param, 118 String match, 119 Function<String, Long> conversion) { 120 long retval = Metrics.unlimited_minimum + 1; // default unlimited 121 try { 122 List<String> lines = subsystem.readMatchingLines(param); 123 for (String line : lines) { 124 if (line.startsWith(match)) { 125 retval = conversion.apply(line); 126 break; 127 } 128 } 129 } catch (IOException e) { 130 // Ignore. Default is unlimited. 131 } 132 return retval; 133 } 134 135 private List<String> readMatchingLines(String param) throws IOException { 136 try { 137 PrivilegedExceptionAction<List<String>> pea = () -> 138 Files.readAllLines(Paths.get(path(), param)); 139 return AccessController.doPrivileged(pea); 140 } catch (PrivilegedActionException e) { 141 Metrics.unwrapIOExceptionAndRethrow(e); 142 throw new InternalError(e.getCause()); 143 } 144 } 145 146 public static long getLongValue(SubSystem subsystem, String parm) { 147 String strval = getStringValue(subsystem, parm); 148 return convertStringToLong(strval); 149 } 150 151 public static long convertStringToLong(String strval) { 152 long retval = 0; 153 if (strval == null) return 0L; 154 155 try { 156 retval = Long.parseLong(strval); 157 } catch (NumberFormatException e) { 158 // For some properties (e.g. memory.limit_in_bytes) we may overflow the range of signed long. 159 // In this case, return Long.MAX_VALUE 160 BigInteger b = new BigInteger(strval); 161 if (b.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { 162 return Long.MAX_VALUE; 163 } 164 } 165 return retval; 166 } 167 168 public static double getDoubleValue(SubSystem subsystem, String parm) { 169 String strval = getStringValue(subsystem, parm); 170 171 if (strval == null) return 0L; 172 173 double retval = Double.parseDouble(strval); 174 175 return retval; 176 } 177 178 /** 179 * getSubSystemlongEntry 180 * 181 * Return the long value from the line containing the string "entryname" 182 * within file "parm" in the "subsystem". 183 * 184 * TODO: Consider using weak references for caching BufferedReader object. 185 * 186 * @param subsystem 187 * @param parm 188 * @param entryname 189 * @return long value 190 */ 191 public static long getLongEntry(SubSystem subsystem, String parm, String entryname) { 192 String val = null; 193 194 if (subsystem == null) return 0L; 195 196 try (Stream<String> lines = Metrics.readFilePrivileged(Paths.get(subsystem.path(), parm))) { 197 198 Optional<String> result = lines.map(line -> line.split(" ")) 199 .filter(line -> (line.length == 2 && 200 line[0].equals(entryname))) 201 .map(line -> line[1]) 202 .findFirst(); 203 204 return result.isPresent() ? Long.parseLong(result.get()) : 0L; 205 } 206 catch (IOException e) { 207 return 0L; 208 } 209 } 210 211 public static int getIntValue(SubSystem subsystem, String parm) { 212 String val = getStringValue(subsystem, parm); 213 214 if (val == null) return 0; 215 216 return Integer.parseInt(val); 217 } 218 219 /** 220 * StringRangeToIntArray 221 * 222 * Convert a string in the form of 1,3-4,6 to an array of 223 * integers containing all the numbers in the range. 224 * 225 * @param range 226 * @return int[] containing a sorted list of processors or memory nodes 227 */ 228 public static int[] StringRangeToIntArray(String range) { 229 int[] ints = new int[0]; 230 231 if (range == null) return ints; 232 233 ArrayList<Integer> results = new ArrayList<>(); 234 String strs[] = range.split(","); 235 for (String str : strs) { 236 if (str.contains("-")) { 237 String lohi[] = str.split("-"); 238 // validate format 239 if (lohi.length != 2) { 240 continue; 241 } 242 int lo = Integer.parseInt(lohi[0]); 243 int hi = Integer.parseInt(lohi[1]); 244 for (int i = lo; i <= hi; i++) { 245 results.add(i); 246 } 247 } 248 else { 249 results.add(Integer.parseInt(str)); 250 } 251 } 252 253 // sort results 254 results.sort(null); 255 256 // convert ArrayList to primitive int array 257 ints = new int[results.size()]; 258 int i = 0; 259 for (Integer n : results) { 260 ints[i++] = n; 261 } 262 263 return ints; 264 } 265 266 public static class MemorySubSystem extends SubSystem { 267 268 private boolean hierarchical; 269 270 public MemorySubSystem(String root, String mountPoint) { 271 super(root, mountPoint); 272 } 273 274 boolean isHierarchical() { 275 return hierarchical; 276 } 277 278 void setHierarchical(boolean hierarchical) { 279 this.hierarchical = hierarchical; 280 } 281 282 } 283 }