gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/util/cgroup_util.h (about) 1 // Copyright 2021 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef GVISOR_TEST_UTIL_CGROUP_UTIL_H_ 16 #define GVISOR_TEST_UTIL_CGROUP_UTIL_H_ 17 18 #include <unistd.h> 19 20 #include "absl/container/flat_hash_map.h" 21 #include "absl/container/flat_hash_set.h" 22 #include "absl/strings/string_view.h" 23 #include "test/util/cleanup.h" 24 #include "test/util/fs_util.h" 25 #include "test/util/temp_path.h" 26 27 namespace gvisor { 28 namespace testing { 29 30 // Cgroup represents a cgroup directory on a mounted cgroupfs. 31 class Cgroup { 32 public: 33 static Cgroup RootCgroup(absl::string_view path) { 34 return Cgroup(path, path); 35 } 36 37 uint64_t id() const { return id_; } 38 39 // Deletes the current cgroup represented by this object. 40 PosixError Delete(); 41 42 const std::string& Path() const { return cgroup_path_; } 43 44 // Returns the canonical path for this cgroup, which is the absolute path 45 // starting at the hierarchy root. 46 const std::string CanonicalPath() const { 47 std::string relpath = 48 GetRelativePath(mountpoint_, cgroup_path_).ValueOrDie(); 49 if (relpath == ".") { 50 return "/"; 51 } 52 return "/" + relpath; 53 } 54 55 // Creates a child cgroup under this cgroup with the given name. 56 PosixErrorOr<Cgroup> CreateChild(absl::string_view name) const; 57 58 std::string Relpath(absl::string_view leaf) const { 59 return JoinPath(cgroup_path_, leaf); 60 } 61 62 // Returns the contents of a cgroup control file with the given name. 63 PosixErrorOr<std::string> ReadControlFile(absl::string_view name) const; 64 65 // Reads the contents of a cgroup control with the given name, and attempts 66 // to parse it as an integer. 67 PosixErrorOr<int64_t> ReadIntegerControlFile(absl::string_view name) const; 68 69 // Writes a string to a cgroup control file. 70 PosixError WriteControlFile(absl::string_view name, 71 const std::string& value) const; 72 73 // Writes an integer value to a cgroup control file. 74 PosixError WriteIntegerControlFile(absl::string_view name, 75 int64_t value) const; 76 77 // Waits for a control file's value to change. 78 PosixError PollControlFileForChange(absl::string_view name, 79 absl::Duration timeout) const; 80 81 // Waits for a control file's value to change after calling body. 82 PosixError PollControlFileForChangeAfter(absl::string_view name, 83 absl::Duration timeout, 84 std::function<void()> body) const; 85 86 // Returns the thread ids of the leaders of thread groups managed by this 87 // cgroup. 88 PosixErrorOr<absl::flat_hash_set<pid_t>> Procs() const; 89 90 PosixErrorOr<absl::flat_hash_set<pid_t>> Tasks() const; 91 92 // ContainsCallingProcess checks whether the calling process is part of the 93 // cgroup. 94 PosixError ContainsCallingProcess() const; 95 96 // ContainsCallingThread checks whether the calling thread is part of the 97 // cgroup. 98 PosixError ContainsCallingThread() const; 99 100 // Moves process with the specified pid to this cgroup. 101 PosixError Enter(pid_t pid) const; 102 103 // Moves thread with the specified pid to this cgroup. 104 PosixError EnterThread(pid_t pid) const; 105 106 private: 107 Cgroup(absl::string_view path, absl::string_view mountpoint); 108 109 PosixErrorOr<absl::flat_hash_set<pid_t>> ParsePIDList( 110 absl::string_view data) const; 111 112 static int64_t next_id_; 113 int64_t id_; 114 const std::string cgroup_path_; 115 const std::string mountpoint_; 116 }; 117 118 // Mounter is a utility for creating cgroupfs mounts. It automatically manages 119 // the lifetime of created mounts. 120 class Mounter { 121 public: 122 Mounter(TempPath root) : root_(std::move(root)) {} 123 124 PosixErrorOr<Cgroup> MountCgroupfs(std::string mopts); 125 126 PosixError Unmount(const Cgroup& c); 127 128 void release(const Cgroup& c); 129 130 private: 131 // The destruction order of these members avoids errors during cleanup. We 132 // first unmount (by executing the mounts_ cleanups), then delete the 133 // mountpoint subdirs, then delete the root. 134 TempPath root_; 135 absl::flat_hash_map<int64_t, TempPath> mountpoints_; 136 absl::flat_hash_map<int64_t, Cleanup> mounts_; 137 }; 138 139 // Represents a line from /proc/cgroups. 140 struct CgroupsEntry { 141 std::string subsys_name; 142 uint32_t hierarchy; 143 uint64_t num_cgroups; 144 bool enabled; 145 }; 146 147 // Returns a parsed representation of /proc/cgroups. 148 PosixErrorOr<absl::flat_hash_map<std::string, CgroupsEntry>> 149 ProcCgroupsEntries(); 150 151 // Represents a line from /proc/<pid>/cgroup. 152 struct PIDCgroupEntry { 153 uint32_t hierarchy; 154 std::string controllers; 155 std::string path; 156 }; 157 158 // Returns a parsed representation of /proc/<pid>/cgroup. 159 PosixErrorOr<absl::flat_hash_map<std::string, PIDCgroupEntry>> 160 ProcPIDCgroupEntries(pid_t pid); 161 162 } // namespace testing 163 } // namespace gvisor 164 165 #endif // GVISOR_TEST_UTIL_CGROUP_UTIL_H_