diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2020-05-16 21:09:48 +0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2020-07-06 13:50:33 +0200 |
commit | 7bdcf43b401eba6aee29a359c5bce1f9cc01ce52 (patch) | |
tree | 2c45186654b9e1f7ef2ae3e2b246407aafbb95e0 /src | |
parent | ca2f64bcdaef5915f5147eac935ecb770511e438 (diff) |
Destroy the cgroup prior to building
Diffstat (limited to 'src')
-rw-r--r-- | src/libstore/build.cc | 8 | ||||
-rw-r--r-- | src/libstore/cgroup.cc | 49 | ||||
-rw-r--r-- | src/libstore/cgroup.hh | 13 |
3 files changed, 66 insertions, 4 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 816d695a5..1f1468d97 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -16,6 +16,7 @@ #include "machines.hh" #include "daemon.hh" #include "worker-protocol.hh" +#include "cgroup.hh" #include <algorithm> #include <iostream> @@ -2400,14 +2401,13 @@ void DerivationGoal::startBuilder() auto hostCgroup = canonPath("/sys/fs/cgroup/" + name + "/" + cgroup); if (!pathExists(hostCgroup)) - throw Error("expected unified cgroup directory '%s'", hostCgroup); + throw Error("expected cgroup directory '%s'", hostCgroup); auto childCgroup = fmt("%s/nix-%d", hostCgroup, buildUser->getUID()); - // FIXME: if the cgroup already exists, kill all processes - // in it and destroy it. + destroyCgroup(childCgroup); - if (mkdir(childCgroup.c_str(), 0755) == -1 && errno != EEXIST) + if (mkdir(childCgroup.c_str(), 0755) == -1) throw SysError("creating cgroup '%s'", childCgroup); chownToBuilder(childCgroup); diff --git a/src/libstore/cgroup.cc b/src/libstore/cgroup.cc new file mode 100644 index 000000000..8cd682e68 --- /dev/null +++ b/src/libstore/cgroup.cc @@ -0,0 +1,49 @@ +#if __linux__ + +#include "cgroup.hh" +#include "util.hh" + +#include <chrono> + +#include <dirent.h> + +namespace nix { + +void destroyCgroup(const Path & cgroup) +{ + for (auto & entry : readDirectory(cgroup)) { + if (entry.type != DT_DIR) continue; + destroyCgroup(cgroup + "/" + entry.name); + } + + int round = 1; + + while (true) { + auto pids = tokenizeString<std::vector<std::string>>(readFile(cgroup + "/cgroup.procs")); + + if (pids.empty()) break; + + if (round > 20) + throw Error("cannot kill cgroup '%s'", cgroup); + + for (auto & pid_s : pids) { + pid_t pid; + if (!string2Int(pid_s, pid)) throw Error("invalid pid '%s'", pid); + // FIXME: pid wraparound + if (kill(pid, SIGKILL) == -1 && errno != ESRCH) + throw SysError("killing member %d of cgroup '%s'", pid, cgroup); + } + + auto sleep = std::chrono::milliseconds((int) std::pow(2.0, std::min(round, 10))); + printError("waiting for %d ms for cgroup '%s' to become empty", sleep.count(), cgroup); + std::this_thread::sleep_for(sleep); + round++; + } + + if (rmdir(cgroup.c_str()) == -1) + throw SysError("deleting cgroup '%s'", cgroup); +} + +} + +#endif diff --git a/src/libstore/cgroup.hh b/src/libstore/cgroup.hh new file mode 100644 index 000000000..c7b09398e --- /dev/null +++ b/src/libstore/cgroup.hh @@ -0,0 +1,13 @@ +#pragma once + +#if __linux__ + +#include "types.hh" + +namespace nix { + +void destroyCgroup(const Path & cgroup); + +} + +#endif |