gtk: clean up per-surface cgroup on close

Fixes #6766

This ensures that during surface deinit the cgroup is removed. By the
time the surface is deinitialized, the subprocess should already be
dead so the cgroup can be safely removed. If the cgroup cannot be
removed for any reason we log a warning.
This commit is contained in:
Mitchell Hashimoto
2025-05-30 16:08:57 -07:00
parent 5667b83328
commit 2b9e781933
2 changed files with 34 additions and 1 deletions

View File

@@ -746,7 +746,21 @@ pub fn deinit(self: *Surface) void {
self.core_surface.deinit();
self.core_surface = undefined;
if (self.cgroup_path) |path| self.app.core_app.alloc.free(path);
// Remove the cgroup if we have one. We do this after deiniting the core
// surface to ensure all processes have exited.
if (self.cgroup_path) |path| {
internal_os.cgroup.remove(path) catch |err| {
// We don't want this to be fatal in any way so we just log
// and continue. A dangling empty cgroup is not a big deal
// and this should be rare.
log.warn(
"failed to remove cgroup for surface path={s} err={}",
.{ path, err },
);
};
self.app.core_app.alloc.free(path);
}
// Free all our GTK stuff
//

View File

@@ -56,6 +56,25 @@ pub fn create(
}
}
/// Remove a cgroup. This will only succeed if the cgroup is empty
/// (has no processes). The cgroup path should be relative to the
/// cgroup root (e.g. "/user.slice/surfaces/abc123.scope").
pub fn remove(cgroup: []const u8) !void {
assert(cgroup.len > 0);
assert(cgroup[0] == '/');
var buf: [std.fs.max_path_bytes]u8 = undefined;
const path = try std.fmt.bufPrint(&buf, "/sys/fs/cgroup{s}", .{cgroup});
std.fs.cwd().deleteDir(path) catch |err| switch (err) {
// If it doesn't exist, that's fine - maybe it was already cleaned up
error.FileNotFound => {},
// Any other error we failed to delete it so we want to notify
// the user.
else => return err,
};
}
/// Move the given PID into the given cgroup.
pub fn moveInto(
cgroup: []const u8,