Skip to content

Commit

Permalink
Fix benchexec when running in empty cgroup with cgroups v2
Browse files Browse the repository at this point in the history
We document that one can start BenchExec in an otherwise cgroup.
However, this works only for runexec so far,
because we check that the current cgroup has exactly one process.
But benchexec starts the tool-info module in a separate process
if container mode is used, and so this check would fail.

We need to relax this and also allow child processes of us
in the given cgroup, and then later on move these child processes
into a different cgroup like our own process
(the existing code does this already).
  • Loading branch information
PhilippWendler committed Jun 7, 2024
1 parent 4fd67dc commit eaf8b12
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
12 changes: 7 additions & 5 deletions benchexec/cgroupsv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ def initialize():

cgroup = CgroupsV2.from_system()

if cgroup.path and list(cgroup.get_all_tasks()) == [os.getpid()]:
# If we are the only process, somebody prepared a cgroup for us. Use it.
# We might be able to relax this check and for example allow child processes,
# but then we would also have to move them to another cgroup,
# which might not be a good idea.
if cgroup.path and all(
util.is_child_process_of_us(pid) for pid in cgroup.get_all_tasks()
):
# If we (and our subprocesses) are the only processes,
# somebody prepared a cgroup for us. Use it.
logging.debug("BenchExec was started in its own cgroup: %s", cgroup)

elif _create_systemd_scope_for_us() or _try_fallback_cgroup():
Expand All @@ -133,6 +133,8 @@ def initialize():
logging.debug("Cgroup found, but cannot create child cgroups: %s", e)
return CgroupsV2({})

# TODO: This moves our subprocesses if they are in the same cgroup.
# We should probably make this consistent and always move them.
for pid in cgroup.get_all_tasks():
child_cgroup.add_task(pid)
assert child_cgroup.has_tasks()
Expand Down
21 changes: 21 additions & 0 deletions benchexec/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,3 +819,24 @@ def check_msr():
if all(os.access(f"/dev/cpu/{cpu}/msr", os.W_OK) for cpu in cpu_dirs):
res["write"] = True
return res


def is_child_process_of_us(pid: int) -> bool:
"""
Return if the given PID is a (transitive) child process of the current process.
Also returns true if the given PID is ours.
"""
if pid == os.getpid():
return True

ppid = None
with open(f"/proc/{pid}/status") as status_file:
for line in status_file:
if line.startswith("PPid:"):
ppid = int(line.split(":", maxsplit=1)[1].strip())
break

if ppid:
return is_child_process_of_us(ppid)
else:
return False

0 comments on commit eaf8b12

Please sign in to comment.