From 2b9e781933834f1123024b275eea1a44afff468d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 30 May 2025 16:08:57 -0700 Subject: [PATCH] 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. --- src/apprt/gtk/Surface.zig | 16 +++++++++++++++- src/os/cgroup.zig | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 3d16e9fbb..e51109015 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -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 // diff --git a/src/os/cgroup.zig b/src/os/cgroup.zig index 5645e337a..4f13921c5 100644 --- a/src/os/cgroup.zig +++ b/src/os/cgroup.zig @@ -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,