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_