This is an automated email from the ASF dual-hosted git repository.

bmahler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git


The following commit(s) were added to refs/heads/master by this push:
     new ea928cee4 [cgroups2] Made `cgroups2::processes` optionally recursive.
ea928cee4 is described below

commit ea928cee466a144fd06d7f75fcc318138c632bc1
Author: Devin Leamy <[email protected]>
AuthorDate: Wed Apr 24 13:05:38 2024 -0400

    [cgroups2] Made `cgroups2::processes` optionally recursive.
    
    Previously, `cgroups2::processes` could only fetch processes
    from inside of the provided cgroup. We can now fetch all of
    the processes inside of a cgroup subtree by passing an
    (optional) `recursive` flag.
    
    ```c++
    Try<std::set<pid_t>> processes(
        const std::string& cgroup,
        bool recursive = false);
    ```
    
    This closes #570
---
 src/linux/cgroups2.cpp                     | 41 +++++++++++++++++++++---------
 src/linux/cgroups2.hpp                     |  6 ++++-
 src/tests/containerizer/cgroups2_tests.cpp |  5 ++++
 3 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/src/linux/cgroups2.cpp b/src/linux/cgroups2.cpp
index f309d604d..ad282695e 100644
--- a/src/linux/cgroups2.cpp
+++ b/src/linux/cgroups2.cpp
@@ -462,29 +462,46 @@ Try<string> cgroup(pid_t pid)
 }
 
 
-Try<set<pid_t>> processes(const string& cgroup)
+Try<set<pid_t>> processes(const string& cgroup, bool recursive)
 {
   if (!cgroups2::exists(cgroup)) {
     return Error("Cgroup '" + cgroup + "' does not exist");
   }
 
-  Try<string> contents = cgroups2::read<string>(cgroup, control::PROCESSES);
-  if (contents.isError()) {
-    return Error(
-        "Failed to read cgroup.procs in '" + cgroup + "': " + 
contents.error());
+  set<string> cgroups = {cgroup};
+
+  if (recursive) {
+    Try<set<string>> descendants = cgroups2::get(cgroup);
+    if (descendants.isError()) {
+      return Error("Failed to list cgroups: " + descendants.error());
+    }
+    cgroups.insert(descendants->begin(), descendants->end());
   }
 
   set<pid_t> pids;
-  foreach (const string& line, strings::split(*contents, "\n")) {
-    if (line.empty()) continue;
 
-    Try<pid_t> pid = numify<pid_t>(line);
-    if (pid.isError()) {
-      return Error(
-          "Failed to parse line '" + line + "' as a pid: " + pid.error());
+  foreach (const string& cgroup, cgroups) {
+    Try<string> contents = cgroups2::read<string>(cgroup, control::PROCESSES);
+
+    if (contents.isError() && !exists(cgroup)) {
+      continue; // Ignore missing cgroups due to races.
+    }
+
+    if (contents.isError()) {
+      return Error("Failed to read cgroup.procs in '" + cgroup + "': "
+                   + contents.error());
     }
 
-    pids.insert(*pid);
+    foreach (const string& line, strings::split(*contents, "\n")) {
+      if (line.empty()) continue;
+
+      Try<pid_t> pid = numify<pid_t>(line);
+      if (pid.isError()) {
+        return Error("Failed to parse '" + line + "' as a pid: " + 
pid.error());
+      }
+
+      pids.insert(*pid);
+    }
   }
 
   return pids;
diff --git a/src/linux/cgroups2.hpp b/src/linux/cgroups2.hpp
index 7060573a4..2639e2f74 100644
--- a/src/linux/cgroups2.hpp
+++ b/src/linux/cgroups2.hpp
@@ -93,7 +93,11 @@ Try<std::string> cgroup(pid_t pid);
 
 
 // Get the processes inside of a cgroup.
-Try<std::set<pid_t>> processes(const std::string& cgroup);
+//
+// Optionally fetch all of the processes in the cgroup subtree by setting
+// recursive=true. This will include all processes in nested cgroups.
+Try<std::set<pid_t>> processes(
+    const std::string& cgroup, bool recursive = false);
 
 
 // Get the threads inside of a cgroup.
diff --git a/src/tests/containerizer/cgroups2_tests.cpp 
b/src/tests/containerizer/cgroups2_tests.cpp
index 592c4bce6..918dfe4ef 100644
--- a/src/tests/containerizer/cgroups2_tests.cpp
+++ b/src/tests/containerizer/cgroups2_tests.cpp
@@ -185,6 +185,11 @@ TEST_F(Cgroups2Test, ROOT_CGROUPS2_AssignProcesses)
   EXPECT_EQ(1u, pids->size());
   EXPECT_EQ(pid, *pids->begin());
 
+  // Should fetch the `pid` from the nested `TEST_CGROUP` if `recursive=true`.
+  Try<set<pid_t>> root_pids = cgroups2::processes(cgroups2::ROOT_CGROUP, true);
+  EXPECT_SOME(pids);
+  EXPECT_EQ(1u, root_pids->count(pid));
+
   // Kill the child process.
   ASSERT_NE(-1, ::kill(pid, SIGKILL));
   AWAIT_EXPECT_WTERMSIG_EQ(SIGKILL, process::reap(pid));

Reply via email to