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.io.UncheckedIOException; 32 import java.nio.file.Files; 33 import java.nio.file.Path; 34 import java.nio.file.Paths; 35 import java.security.AccessController; 36 import java.security.PrivilegedActionException; 37 import java.security.PrivilegedExceptionAction; 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Optional; 41 import java.util.function.Function; 42 import java.util.stream.Stream; 43 44 public class SubSystem { 45 String root; 46 String mountPoint; 47 String path; 48 SubSystem(String root, String mountPoint)49 public SubSystem(String root, String mountPoint) { 50 this.root = root; 51 this.mountPoint = mountPoint; 52 } 53 setPath(String cgroupPath)54 public void setPath(String cgroupPath) { 55 if (root != null && cgroupPath != null) { 56 if (root.equals("/")) { 57 if (!cgroupPath.equals("/")) { 58 path = mountPoint + cgroupPath; 59 } 60 else { 61 path = mountPoint; 62 } 63 } 64 else { 65 if (root.equals(cgroupPath)) { 66 path = mountPoint; 67 } 68 else { 69 if (cgroupPath.startsWith(root)) { 70 if (cgroupPath.length() > root.length()) { 71 String cgroupSubstr = cgroupPath.substring(root.length()); 72 path = mountPoint + cgroupSubstr; 73 } 74 } 75 } 76 } 77 } 78 } 79 path()80 public String path() { 81 return path; 82 } 83 84 /** 85 * getSubSystemStringValue 86 * 87 * Return the first line of the file "parm" argument from the subsystem. 88 * 89 * TODO: Consider using weak references for caching BufferedReader object. 90 * 91 * @param subsystem 92 * @param parm 93 * @return Returns the contents of the file specified by param. 94 */ getStringValue(SubSystem subsystem, String parm)95 public static String getStringValue(SubSystem subsystem, String parm) { 96 if (subsystem == null) return null; 97 98 try { 99 return subsystem.readStringValue(parm); 100 } catch (IOException e) { 101 return null; 102 } 103 } 104 readStringValue(String param)105 private String readStringValue(String param) throws IOException { 106 PrivilegedExceptionAction<BufferedReader> pea = () -> 107 Files.newBufferedReader(Paths.get(path(), param)); 108 try (BufferedReader bufferedReader = 109 AccessController.doPrivileged(pea)) { 110 String line = bufferedReader.readLine(); 111 return line; 112 } catch (PrivilegedActionException e) { 113 Metrics.unwrapIOExceptionAndRethrow(e); 114 throw new InternalError(e.getCause()); 115 } catch (UncheckedIOException e) { 116 throw e.getCause(); 117 } 118 } 119 getLongValueMatchingLine(SubSystem subsystem, String param, String match, Function<String, Long> conversion)120 public static long getLongValueMatchingLine(SubSystem subsystem, 121 String param, 122 String match, 123 Function<String, Long> conversion) { 124 long retval = Metrics.unlimited_minimum + 1; // default unlimited 125 try { 126 List<String> lines = subsystem.readMatchingLines(param); 127 for (String line: lines) { 128 if (line.contains(match)) { 129 retval = conversion.apply(line); 130 break; 131 } 132 } 133 } catch (IOException e) { 134 // Ignore. Default is unlimited. 135 } 136 return retval; 137 } 138 readMatchingLines(String param)139 private List<String> readMatchingLines(String param) throws IOException { 140 try { 141 PrivilegedExceptionAction<List<String>> pea = () -> 142 Files.readAllLines(Paths.get(path(), param)); 143 return AccessController.doPrivileged(pea); 144 } catch (PrivilegedActionException e) { 145 Metrics.unwrapIOExceptionAndRethrow(e); 146 throw new InternalError(e.getCause()); 147 } catch (UncheckedIOException e) { 148 throw e.getCause(); 149 } 150 } 151 getLongValue(SubSystem subsystem, String parm)152 public static long getLongValue(SubSystem subsystem, String parm) { 153 String strval = getStringValue(subsystem, parm); 154 return convertStringToLong(strval); 155 } 156 convertStringToLong(String strval)157 public static long convertStringToLong(String strval) { 158 if (strval == null) return 0L; 159 160 long retval = 0; 161 162 try { 163 retval = Long.parseLong(strval); 164 } catch (NumberFormatException e) { 165 // For some properties (e.g. memory.limit_in_bytes) we may overflow the range of signed long. 166 // In this case, return Long.max 167 BigInteger b = new BigInteger(strval); 168 if (b.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { 169 return Long.MAX_VALUE; 170 } 171 } 172 173 return retval; 174 } 175 getDoubleValue(SubSystem subsystem, String parm)176 public static double getDoubleValue(SubSystem subsystem, String parm) { 177 String strval = getStringValue(subsystem, parm); 178 179 if (strval == null) return 0L; 180 181 double retval = Double.parseDouble(strval); 182 183 return retval; 184 } 185 186 /** 187 * getSubSystemlongEntry 188 * 189 * Return the long value from the line containing the string "entryname" 190 * within file "parm" in the "subsystem". 191 * 192 * TODO: Consider using weak references for caching BufferedReader object. 193 * 194 * @param subsystem 195 * @param parm 196 * @param entryname 197 * @return long value 198 */ getLongEntry(SubSystem subsystem, String parm, String entryname)199 public static long getLongEntry(SubSystem subsystem, String parm, String entryname) { 200 String val = null; 201 202 if (subsystem == null) return 0L; 203 204 try (Stream<String> lines = Metrics.readFilePrivileged(Paths.get(subsystem.path(), parm))) { 205 206 Optional<String> result = lines.map(line -> line.split(" ")) 207 .filter(line -> (line.length == 2 && 208 line[0].equals(entryname))) 209 .map(line -> line[1]) 210 .findFirst(); 211 212 return result.isPresent() ? Long.parseLong(result.get()) : 0L; 213 } catch (IOException e) { 214 return 0L; 215 } catch (UncheckedIOException e) { 216 return 0L; 217 } 218 } 219 getIntValue(SubSystem subsystem, String parm)220 public static int getIntValue(SubSystem subsystem, String parm) { 221 String val = getStringValue(subsystem, parm); 222 223 if (val == null) return 0; 224 225 return Integer.parseInt(val); 226 } 227 228 /** 229 * StringRangeToIntArray 230 * 231 * Convert a string in the form of 1,3-4,6 to an array of 232 * integers containing all the numbers in the range. 233 * 234 * @param range 235 * @return int[] containing a sorted list of processors or memory nodes 236 */ StringRangeToIntArray(String range)237 public static int[] StringRangeToIntArray(String range) { 238 int[] ints = new int[0]; 239 240 if (range == null) return ints; 241 242 ArrayList<Integer> results = new ArrayList<>(); 243 String strs[] = range.split(","); 244 for (String str : strs) { 245 if (str.contains("-")) { 246 String lohi[] = str.split("-"); 247 // validate format 248 if (lohi.length != 2) { 249 continue; 250 } 251 int lo = Integer.parseInt(lohi[0]); 252 int hi = Integer.parseInt(lohi[1]); 253 for (int i = lo; i <= hi; i++) { 254 results.add(i); 255 } 256 } 257 else { 258 results.add(Integer.parseInt(str)); 259 } 260 } 261 262 // sort results 263 results.sort(null); 264 265 // convert ArrayList to primitive int array 266 ints = new int[results.size()]; 267 int i = 0; 268 for (Integer n : results) { 269 ints[i++] = n; 270 } 271 272 return ints; 273 } 274 275 public static class MemorySubSystem extends SubSystem { 276 277 private boolean hierarchical; 278 private boolean swapenabled; 279 MemorySubSystem(String root, String mountPoint)280 public MemorySubSystem(String root, String mountPoint) { 281 super(root, mountPoint); 282 } 283 isHierarchical()284 boolean isHierarchical() { 285 return hierarchical; 286 } 287 setHierarchical(boolean hierarchical)288 void setHierarchical(boolean hierarchical) { 289 this.hierarchical = hierarchical; 290 } 291 isSwapEnabled()292 boolean isSwapEnabled() { 293 return swapenabled; 294 } 295 setSwapEnabled(boolean swapenabled)296 void setSwapEnabled(boolean swapenabled) { 297 this.swapenabled = swapenabled; 298 } 299 300 } 301 } 302