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
commit 60283dfed06a5fff4ecedaba4e67674dc01aa16e Author: Devin Leamy <[email protected]> AuthorDate: Fri Mar 22 11:45:03 2024 -0400 [cgroups2] Add an interface to read and assign processes. `cgroup.procs` lists all of the processes inside of a cgroup, one per line. There may be duplicates. A single process can be moved into a cgroup by writing its process ID into `cgroup.procs`. Here we introduce: - Reading the processes inside of a cgroup, and - Assigning a process to a cgroup. This closes #532 --- src/linux/cgroups2.cpp | 41 ++++++++++++++++++++++++++++++ src/linux/cgroups2.hpp | 9 +++++++ src/tests/containerizer/cgroups2_tests.cpp | 37 +++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/src/linux/cgroups2.cpp b/src/linux/cgroups2.cpp index c2892f544..310119bc8 100644 --- a/src/linux/cgroups2.cpp +++ b/src/linux/cgroups2.cpp @@ -357,6 +357,47 @@ Try<string> cgroup(pid_t pid) } +Try<set<pid_t>> processes(const string& cgroup) +{ + 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()); + } + + string trimmed = strings::trim(*contents); + if (trimmed.empty()) { + return set<pid_t>(); + } + + set<pid_t> pids; + foreach (const string& _pid, strings::split(strings::trim(*contents), "\n")) { + Try<pid_t> pid = numify<pid_t>(strings::trim(_pid)); + if (pid.isError()) { + return Error("Failed to parse pid: " + pid.error()); + } + + pids.insert(*pid); + } + + return pids; +} + + +Try<Nothing> assign(const string& cgroup, pid_t pid) +{ + if (!cgroups2::exists(cgroup)) { + return Error("Cgroup '" + cgroup + "' does not exist"); + } + + return cgroups2::write(cgroup, control::PROCESSES, stringify(pid)); +} + + string path(const string& cgroup) { return path::join(cgroups2::MOUNT_POINT, cgroup); diff --git a/src/linux/cgroups2.hpp b/src/linux/cgroups2.hpp index ea3e577f9..9c9b9ceef 100644 --- a/src/linux/cgroups2.hpp +++ b/src/linux/cgroups2.hpp @@ -76,6 +76,15 @@ Try<Nothing> move_process(const std::string& cgroup, pid_t pid); Try<std::string> cgroup(pid_t pid); +// Get the processes inside of a cgroup. +Try<std::set<pid_t>> processes(const std::string& cgroup); + + +// Assign a process to a cgroup, by PID. This removes the process from its +// current cgroup. +Try<Nothing> assign(const std::string& cgroup, pid_t pid); + + // Get the absolute of a cgroup. The cgroup provided should not start with '/'. std::string path(const std::string& cgroup); diff --git a/src/tests/containerizer/cgroups2_tests.cpp b/src/tests/containerizer/cgroups2_tests.cpp index ee3932e0e..756292096 100644 --- a/src/tests/containerizer/cgroups2_tests.cpp +++ b/src/tests/containerizer/cgroups2_tests.cpp @@ -123,6 +123,43 @@ TEST_F(Cgroups2Test, CGROUPS2_Path) EXPECT_EQ("/sys/fs/cgroup/foo/bar", cgroups2::path("foo/bar")); } + +TEST_F(Cgroups2Test, CGROUPS_Path) +{ + Try<set<pid_t>> pids = cgroups2::processes(cgroups2::ROOT_CGROUP); + + EXPECT_SOME(pids); + EXPECT_TRUE(pids->size() > 0); + + ASSERT_SOME(cgroups2::create(TEST_CGROUP)); + + pid_t pid = ::fork(); + ASSERT_NE(-1, pid); + + if (pid == 0) { + // In child process, wait for kill signal. + while (true) { sleep(1); } + + SAFE_EXIT( + EXIT_FAILURE, "Error, child should be killed before reaching here"); + } + + pids = cgroups2::processes(TEST_CGROUP); + EXPECT_SOME(pids); + EXPECT_EQ(0u, pids->size()); + + EXPECT_SOME(cgroups2::assign(TEST_CGROUP, pid)); + pids = cgroups2::processes(TEST_CGROUP); + + EXPECT_SOME(pids); + EXPECT_EQ(1u, pids->size()); + EXPECT_EQ(pid, *pids->begin()); + + // Kill the child process. + ASSERT_NE(-1, ::kill(pid, SIGKILL)); + AWAIT_EXPECT_WTERMSIG_EQ(SIGKILL, process::reap(pid)); +} + } // namespace tests { } // namespace internal {
