/* * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #ifndef CGROUP_SUBSYSTEM_LINUX_HPP #define CGROUP_SUBSYSTEM_LINUX_HPP #include "memory/allocation.hpp" #include "runtime/os.hpp" #include "logging/log.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "osContainer_linux.hpp" // Shared cgroups code (used by cgroup version 1 and version 2) /* * PER_CPU_SHARES has been set to 1024 because CPU shares' quota * is commonly used in cloud frameworks like Kubernetes[1], * AWS[2] and Mesos[3] in a similar way. They spawn containers with * --cpu-shares option values scaled by PER_CPU_SHARES. Thus, we do * the inverse for determining the number of possible available * CPUs to the JVM inside a container. See JDK-8216366. * * [1] https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu * In particular: * When using Docker: * The spec.containers[].resources.requests.cpu is converted to its core value, which is potentially * fractional, and multiplied by 1024. The greater of this number or 2 is used as the value of the * --cpu-shares flag in the docker run command. * [2] https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html * [3] https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/docker/docker.cpp#L648 * https://github.com/apache/mesos/blob/3478e344fb77d931f6122980c6e94cd3913c441d/src/slave/containerizer/mesos/isolators/cgroups/constants.hpp#L30 */ #define PER_CPU_SHARES 1024 typedef char * cptr; class CgroupController: CHeapObj { friend class CgroupSubsystemFactory; public: virtual char *subsystem_path(); }; PRAGMA_DIAG_PUSH PRAGMA_FORMAT_NONLITERAL_IGNORED template int subsystem_file_line_contents(CgroupController* c, const char *filename, const char *matchline, const char *scan_fmt, T returnval) { FILE *fp = NULL; char *p; char file[MAXPATHLEN+1]; char buf[MAXPATHLEN+1]; char discard[MAXPATHLEN+1]; bool found_match = false; if (c == NULL) { log_debug(os, container)("subsystem_file_line_contents: CgroupController* is NULL"); return OSCONTAINER_ERROR; } if (c->subsystem_path() == NULL) { log_debug(os, container)("subsystem_file_line_contents: subsystem path is NULL"); return OSCONTAINER_ERROR; } strncpy(file, c->subsystem_path(), MAXPATHLEN); file[MAXPATHLEN-1] = '\0'; int filelen = strlen(file); if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) { log_debug(os, container)("File path too long %s, %s", file, filename); return OSCONTAINER_ERROR; } strncat(file, filename, MAXPATHLEN-filelen); log_trace(os, container)("Path to %s is %s", filename, file); fp = fopen(file, "r"); if (fp != NULL) { int err = 0; while ((p = fgets(buf, MAXPATHLEN, fp)) != NULL) { found_match = false; if (matchline == NULL) { // single-line file case int matched = sscanf(p, scan_fmt, returnval); found_match = (matched == 1); } else { // multi-line file case if (strstr(p, matchline) != NULL) { // discard matchline string prefix int matched = sscanf(p, scan_fmt, discard, returnval); found_match = (matched == 2); } else { continue; // substring not found } } if (found_match) { fclose(fp); return 0; } else { err = 1; log_debug(os, container)("Type %s not found in file %s", scan_fmt, file); } } if (err == 0) { log_debug(os, container)("Empty file %s", file); } } else { log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno)); } if (fp != NULL) fclose(fp); return OSCONTAINER_ERROR; } PRAGMA_DIAG_POP #define GET_CONTAINER_INFO(return_type, subsystem, filename, \ logstring, scan_fmt, variable) \ return_type variable; \ { \ int err; \ err = subsystem_file_line_contents(subsystem, \ filename, \ NULL, \ scan_fmt, \ &variable); \ if (err != 0) \ return (return_type) OSCONTAINER_ERROR; \ \ log_trace(os, container)(logstring, variable); \ } #define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \ logstring, scan_fmt, variable, bufsize) \ char variable[bufsize]; \ { \ int err; \ err = subsystem_file_line_contents(subsystem, \ filename, \ NULL, \ scan_fmt, \ variable); \ if (err != 0) \ return (return_type) NULL; \ \ log_trace(os, container)(logstring, variable); \ } #define GET_CONTAINER_INFO_LINE(return_type, controller, filename, \ matchline, logstring, scan_fmt, variable) \ return_type variable; \ { \ int err; \ err = subsystem_file_line_contents(controller, \ filename, \ matchline, \ scan_fmt, \ &variable); \ if (err != 0) \ return (return_type) OSCONTAINER_ERROR; \ \ log_trace(os, container)(logstring, variable); \ } class CgroupSubsystem: CHeapObj { friend class CgroupSubsystemFactory; public: int active_processor_count(int physical_proc_count); virtual int cpu_quota(); virtual int cpu_period(); virtual int cpu_shares(); virtual jlong memory_usage_in_bytes(); virtual jlong memory_and_swap_limit_in_bytes(); virtual jlong memory_soft_limit_in_bytes(); virtual jlong memory_max_usage_in_bytes(); virtual char * cpu_cpuset_cpus(); virtual char * cpu_cpuset_memory_nodes(); virtual jlong memory_limit_in_bytes(); virtual const char * container_type(); }; class CgroupSubsystemFactory: AllStatic { public: static CgroupSubsystem* create(); }; #endif // CGROUP_SUBSYSTEM_LINUX_HPP