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