git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitd32fa8c62bc0d9e088d765e81e79a51c2fcbbae8
parent394660bff7
authorIsaac Freund <[email protected]>
date2020-08-01 17:27
server: handle SIGINT/SIGTERM with wl_event_loop

This is cleaner than having a separate signal handler and should be more
consistent/reliable.

 river/Root.zig   |  2 +-
 river/Server.zig | 22 ++++++++++++++++++++--
 river/main.zig   | 19 +------------------
 3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/river/Root.zig b/river/Root.zig
index 95ab9db..c286c90 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -69,7 +69,7 @@ pub fn init(self: *Self, server: *Server) !void {
     self.pending_configures = 0;
 
     self.transaction_timer = c.wl_event_loop_add_timer(
-        self.server.wl_event_loop,
+        c.wl_display_get_event_loop(self.server.wl_display),
         handleTimeout,
         self,
     ) orelse return error.AddTimerError;
diff --git a/river/Server.zig b/river/Server.zig
index 66af1e7..e06e1c6 100644
--- a/river/Server.zig
+++ b/river/Server.zig
@@ -37,7 +37,9 @@ const ViewStack = @import("view_stack.zig").ViewStack;
 const XwaylandUnmanaged = @import("XwaylandUnmanaged.zig");
 
 wl_display: *c.wl_display,
-wl_event_loop: *c.wl_event_loop,
+
+sigint_source: *c.wl_event_source,
+sigterm_source: *c.wl_event_source,
 
 wlr_backend: *c.wlr_backend,
 noop_backend: *c.wlr_backend,
@@ -66,7 +68,13 @@ pub fn init(self: *Self) !void {
     errdefer c.wl_display_destroy(self.wl_display);
 
     // Never returns null if the display was created successfully
-    self.wl_event_loop = c.wl_display_get_event_loop(self.wl_display).?;
+    const wl_event_loop = c.wl_display_get_event_loop(self.wl_display);
+    self.sigint_source = c.wl_event_loop_add_signal(wl_event_loop, std.os.SIGINT, terminate, self.wl_display) orelse
+        return error.AddEventSourceFailed;
+    errdefer _ = c.wl_event_source_remove(self.sigint_source);
+    self.sigterm_source = c.wl_event_loop_add_signal(wl_event_loop, std.os.SIGTERM, terminate, self.wl_display) orelse
+        return error.AddEventSourceFailed;
+    errdefer _ = c.wl_event_source_remove(self.sigterm_source);
 
     // The wlr_backend abstracts the input/output hardware. Autocreate chooses
     // the best option based on the environment, for example DRM when run from
@@ -129,6 +137,9 @@ pub fn init(self: *Self) !void {
 /// Free allocated memory and clean up
 pub fn deinit(self: *Self) void {
     // Note: order is important here
+    _ = c.wl_event_source_remove(self.sigint_source);
+    _ = c.wl_event_source_remove(self.sigterm_source);
+
     if (build_options.xwayland) c.wlr_xwayland_destroy(self.wlr_xwayland);
 
     c.wl_display_destroy_clients(self.wl_display);
@@ -157,6 +168,13 @@ pub fn run(self: Self) void {
     c.wl_display_run(self.wl_display);
 }
 
+/// Handle SIGINT and SIGTERM by gracefully stopping the server
+fn terminate(signal: c_int, data: ?*c_void) callconv(.C) c_int {
+    const wl_display = util.voidCast(c.wl_display, data.?);
+    c.wl_display_terminate(wl_display);
+    return 0;
+}
+
 fn handleNewOutput(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
     const self = @fieldParentPtr(Self, "listen_new_output", listener.?);
     const wlr_output = util.voidCast(c.wlr_output, data.?);
diff --git a/river/main.zig b/river/main.zig
index 0de1856..7e47ec4 100644
--- a/river/main.zig
+++ b/river/main.zig
@@ -32,8 +32,6 @@ const usage: []const u8 =
     \\
 ;
 
-var server: Server = undefined;
-
 pub fn main() anyerror!void {
     var startup_command: ?[*:0]const u8 = null;
     {
@@ -71,15 +69,7 @@ pub fn main() anyerror!void {
 
     log.info(.server, "initializing", .{});
 
-    // Setup a handler for SIGINT and SIGTERM so we can clean up properly
-    var act = std.os.Sigaction{
-        .sigaction = handleSignal,
-        .mask = std.os.empty_sigset,
-        .flags = 0,
-    };
-    std.os.sigaction(std.os.SIGINT, &act, null);
-    std.os.sigaction(std.os.SIGTERM, &act, null);
-
+    var server: Server = undefined;
     try server.init();
     defer server.deinit();
 
@@ -109,10 +99,3 @@ fn printErrorExit(comptime format: []const u8, args: var) noreturn {
     stderr.print(format ++ "\n", args) catch std.os.exit(1);
     std.os.exit(1);
 }
-
-fn handleSignal(sig: i32, info: *const std.os.siginfo_t, ctx_ptr: ?*const c_void) callconv(.C) void {
-    switch (sig) {
-        std.os.SIGINT, std.os.SIGTERM => c.wl_display_terminate(server.wl_display),
-        else => unreachable,
-    }
-}