diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/apprt/gtk/cgroup.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/apprt/gtk/cgroup.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/apprt/gtk/cgroup.zig | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/apprt/gtk/cgroup.zig b/vendor/libghostty-vt/src/apprt/gtk/cgroup.zig new file mode 100644 index 00000000..868aa268 --- /dev/null +++ b/vendor/libghostty-vt/src/apprt/gtk/cgroup.zig @@ -0,0 +1,115 @@ +/// Contains all the logic for putting individual surfaces into +/// transient systemd scopes. +const std = @import("std"); +const Allocator = std.mem.Allocator; +const assert = @import("../../quirks.zig").inlineAssert; + +const gio = @import("gio"); +const glib = @import("glib"); + +const internal_os = @import("../../os/main.zig"); + +const log = std.log.scoped(.gtk_systemd_cgroup); + +pub const Options = struct { + memory_high: ?u64 = null, + tasks_max: ?u64 = null, +}; + +pub fn fmtScope(buf: []u8, pid: u32) [:0]const u8 { + const fmt = "app-ghostty-surface-transient-{}.scope"; + + assert(buf.len >= fmt.len - 2 + std.math.log10_int(@as(usize, std.math.maxInt(@TypeOf(pid)))) + 1); + + return std.fmt.bufPrintZ(buf, fmt, .{pid}) catch unreachable; +} + +/// Create a transient systemd scope unit for the given process and +/// move the process into it. +pub fn createScope( + dbus: *gio.DBusConnection, + pid: u32, + options: Options, +) error{DbusCallFailed}!void { + // The unit name needs to be unique. We use the PID for this. + var name_buf: [256]u8 = undefined; + const name = fmtScope(&name_buf, pid); + + const builder_type = glib.VariantType.new("(ssa(sv)a(sa(sv)))"); + defer glib.free(builder_type); + + // Initialize our builder to build up our parameters + var builder: glib.VariantBuilder = undefined; + builder.init(builder_type); + + builder.add("s", name.ptr); + builder.add("s", "fail"); + + { + // Properties + const properties_type = glib.VariantType.new("a(sv)"); + defer glib.free(properties_type); + + builder.open(properties_type); + defer builder.close(); + + if (options.memory_high) |value| { + builder.add("(sv)", "MemoryHigh", glib.Variant.newUint64(value)); + } + + if (options.tasks_max) |value| { + builder.add("(sv)", "TasksMax", glib.Variant.newUint64(value)); + } + + // https://www.freedesktop.org/software/systemd/man/latest/systemd-oomd.service.html + builder.add("(sv)", "ManagedOOMMemoryPressure", glib.Variant.newString("kill")); + + // PID to move into the unit + const pids_value_type = glib.VariantType.new("u"); + defer glib.free(pids_value_type); + + const pids_value = glib.Variant.newFixedArray(pids_value_type, &pid, 1, @sizeOf(u32)); + + builder.add("(sv)", "PIDs", pids_value); + } + + { + // Aux - unused but must be present + const aux_type = glib.VariantType.new("a(sa(sv))"); + defer glib.free(aux_type); + + builder.open(aux_type); + defer builder.close(); + } + + var err: ?*glib.Error = null; + defer if (err) |e| e.free(); + + const reply_type = glib.VariantType.new("(o)"); + defer glib.free(reply_type); + + const value = builder.end(); + + const reply = dbus.callSync( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartTransientUnit", + value, + reply_type, + .{}, + -1, + null, + &err, + ) orelse { + if (err) |e| log.err( + "creating transient cgroup scope failed code={} err={s}", + .{ + e.f_code, + if (e.f_message) |msg| msg else "(no message)", + }, + ); + return error.DbusCallFailed; + }; + defer reply.unref(); +} |
