1 /* 2 * Copyright (c) 2019, Red Hat Inc. 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; 27 28 import java.io.IOException; 29 import java.math.BigInteger; 30 import java.nio.file.Path; 31 import java.nio.file.Paths; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Optional; 35 import java.util.function.Function; 36 import java.util.stream.Stream; 37 38 /** 39 * Cgroup version agnostic controller logic 40 * 41 */ 42 public interface CgroupSubsystemController { 43 44 public static final long RETVAL_UNLIMITED = -1; 45 public static final long RETVAL_NOT_SUPPORTED = -2; 46 public static final long RETVAL_ERROR = -3; 47 public static final String EMPTY_STR = ""; 48 49 public String path(); 50 51 /** 52 * getStringValue 53 * 54 * Return the first line of the file "parm" argument from the controller. 55 * 56 * TODO: Consider using weak references for caching BufferedReader object. 57 * 58 * @param controller 59 * @param parm 60 * @return Returns the contents of the file specified by param. 61 */ 62 public static String getStringValue(CgroupSubsystemController controller, String param) { 63 if (controller == null) return null; 64 65 try { 66 return CgroupUtil.readStringValue(controller, param); 67 } 68 catch (IOException e) { 69 return null; 70 } 71 72 } 73 74 public static long getLongValueMatchingLine(CgroupSubsystemController controller, 75 String param, 76 String match, 77 Function<String, Long> conversion) { 78 long retval = CgroupSubsystemController.RETVAL_UNLIMITED; 79 try { 80 Path filePath = Paths.get(controller.path(), param); 81 List<String> lines = CgroupUtil.readAllLinesPrivileged(filePath); 82 for (String line : lines) { 83 if (line.startsWith(match)) { 84 retval = conversion.apply(line); 85 break; 86 } 87 } 88 } catch (IOException e) { 89 // Ignore. Default is unlimited. 90 } 91 return retval; 92 } 93 94 public static long getLongValue(CgroupSubsystemController controller, 95 String parm, 96 Function<String, Long> conversion) { 97 String strval = getStringValue(controller, parm); 98 return conversion.apply(strval); 99 } 100 101 public static double getDoubleValue(CgroupSubsystemController controller, String parm) { 102 String strval = getStringValue(controller, parm); 103 104 if (strval == null) return 0L; 105 106 double retval = Double.parseDouble(strval); 107 108 return retval; 109 } 110 111 /** 112 * getSubSystemlongEntry 113 * 114 * Return the long value from the line containing the string "entryname" 115 * within file "parm" in the "subsystem". 116 * 117 * TODO: Consider using weak references for caching BufferedReader object. 118 * 119 * @param controller 120 * @param parm 121 * @param entryname 122 * @return long value 123 */ 124 public static long getLongEntry(CgroupSubsystemController controller, String parm, String entryname) { 125 if (controller == null) return 0L; 126 127 try (Stream<String> lines = CgroupUtil.readFilePrivileged(Paths.get(controller.path(), parm))) { 128 129 Optional<String> result = lines.map(line -> line.split(" ")) 130 .filter(line -> (line.length == 2 && 131 line[0].equals(entryname))) 132 .map(line -> line[1]) 133 .findFirst(); 134 135 return result.isPresent() ? Long.parseLong(result.get()) : 0L; 136 } 137 catch (IOException e) { 138 return 0L; 139 } 140 } 141 142 /** 143 * StringRangeToIntArray 144 * 145 * Convert a string in the form of 1,3-4,6 to an array of 146 * integers containing all the numbers in the range. 147 * 148 * @param range 149 * @return int[] containing a sorted list of processors or memory nodes 150 */ 151 public static int[] stringRangeToIntArray(String range) { 152 int[] ints = new int[0]; 153 154 if (range == null || EMPTY_STR.equals(range)) return ints; 155 156 ArrayList<Integer> results = new ArrayList<>(); 157 String strs[] = range.split(","); 158 for (String str : strs) { 159 if (str.contains("-")) { 160 String lohi[] = str.split("-"); 161 // validate format 162 if (lohi.length != 2) { 163 continue; 164 } 165 int lo = Integer.parseInt(lohi[0]); 166 int hi = Integer.parseInt(lohi[1]); 167 for (int i = lo; i <= hi; i++) { 168 results.add(i); 169 } 170 } 171 else { 172 results.add(Integer.parseInt(str)); 173 } 174 } 175 176 // sort results 177 results.sort(null); 178 179 // convert ArrayList to primitive int array 180 ints = new int[results.size()]; 181 int i = 0; 182 for (Integer n : results) { 183 ints[i++] = n; 184 } 185 186 return ints; 187 } 188 189 public static long convertStringToLong(String strval, long overflowRetval) { 190 long retval = 0; 191 if (strval == null) return 0L; 192 193 try { 194 retval = Long.parseLong(strval); 195 } catch (NumberFormatException e) { 196 // For some properties (e.g. memory.limit_in_bytes) we may overflow 197 // the range of signed long. In this case, return unlimited 198 BigInteger b = new BigInteger(strval); 199 if (b.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { 200 return overflowRetval; 201 } 202 } 203 return retval; 204 } 205 206 }