diff --git a/benchexec/cgroupsv2.py b/benchexec/cgroupsv2.py index 9e6c164fb..79dd14148 100644 --- a/benchexec/cgroupsv2.py +++ b/benchexec/cgroupsv2.py @@ -109,9 +109,9 @@ def initialize(): # which might not be a good idea. logging.debug("BenchExec was started in its own cgroup: %s", cgroup) - elif _create_systemd_scope_for_us(): - # If we can create a systemd scope for us and move ourselves in it, - # we have a usable cgroup afterwards. + elif _create_systemd_scope_for_us() or _try_fallback_cgroup(): + # If we can create a systemd scope for us or find a usable fallback cgroup + # and move ourselves in it, we have a usable cgroup afterwards. cgroup = CgroupsV2.from_system() else: @@ -192,6 +192,32 @@ def _create_systemd_scope_for_us(): return False +def _try_fallback_cgroup(): + """ + Attempt to locate a usable fallback cgroup. + If it is found this process is moved into it. + + @return: a boolean indicating whether this succeeded + """ + # Attempt to use /benchexec cgroup. + # If it exists, some deliberately created it for us to use. + # The following does this by just faking a /proc/self/cgroup for this case. + cgroup = CgroupsV2.from_system(["0::/benchexec"]) + if cgroup.path and not list(cgroup.get_all_tasks()): + logging.debug("Found existing cgroup /benchexec, using it as fallback.") + + # Create cgroup for this execution of BenchExec. + cgroup = cgroup.create_fresh_child_cgroup( + cgroup.subsystems.keys(), prefix="benchexec_" + ) + # Move ourselves to it such that for the rest of the code this looks as usual. + cgroup.add_task(os.getpid()) + + return True + + return False + + def _find_cgroup_mount(): """ Return the mountpoint of the cgroupv2 unified hierarchy. diff --git a/doc/INSTALL.md b/doc/INSTALL.md index cb1816876..3eabb5869 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -351,6 +351,23 @@ For both Podman and Docker this will work if BenchExec is the main process inside the container, otherwise you need to manually create an appropriate cgroup hierarchy inside the container, i.e., one where BenchExec has its own separate cgroup. +You can either start BenchExec as the only process in a fresh cgroup +or create an empty cgroup named `/benchexec`, +which BenchExec will then automatically use. +This cgroup should have as many controllers enabled and delegated to sub-cgroups as possible, +for example like this: +``` +mkdir -p /sys/fs/cgroup/benchexec +for controller in $(cat /sys/fs/cgroup/cgroup.controllers); do + echo "+$controller" > /sys/fs/cgroup/cgroup.subtree_control +done +for controller in $(cat /sys/fs/cgroup/benchexec/cgroup.controllers); do + echo "+$controller" > /sys/fs/cgroup/benchexec/cgroup.subtree_control +done +``` +Note that if no other cgroups exist, +you first need to create a different child cgroup +for all existing processes in the container. For systems with cgroups v1, please use the following command line argument