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,