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