From 341fe1e977cd44164f238030acc03bf7426f179d Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 5 Jul 2020 22:49:17 +0200 Subject: [PATCH] code: handle out of memory as well as possible --- build.zig | 4 ++-- river/Decoration.zig | 14 ++------------ river/DecorationManager.zig | 8 +++++--- river/InputManager.zig | 4 +--- river/LayerSurface.zig | 5 ++++- river/Root.zig | 12 +++++++++--- river/Seat.zig | 28 ++++++++++++++-------------- river/Server.zig | 14 ++++++++++---- river/XdgPopup.zig | 5 ++++- river/XdgToplevel.zig | 5 ++++- 10 files changed, 55 insertions(+), 44 deletions(-) diff --git a/build.zig b/build.zig index 20e1ae2..8a9572b 100644 --- a/build.zig +++ b/build.zig @@ -130,7 +130,7 @@ const ScanProtocolsStep = struct { step: std.build.Step, fn create(builder: *std.build.Builder) *ScanProtocolsStep { - const self = builder.allocator.create(ScanProtocolsStep) catch unreachable; + const self = builder.allocator.create(ScanProtocolsStep) catch @panic("out of memory"); self.* = init(builder); return self; } @@ -225,7 +225,7 @@ const ScdocStep = struct { step: std.build.Step, fn create(builder: *std.build.Builder) *ScdocStep { - const self = builder.allocator.create(ScdocStep) catch unreachable; + const self = builder.allocator.create(ScdocStep) catch @panic("out of memory"); self.* = init(builder); return self; } diff --git a/river/Decoration.zig b/river/Decoration.zig index 863ae3f..44f48c2 100644 --- a/river/Decoration.zig +++ b/river/Decoration.zig @@ -22,10 +22,6 @@ const std = @import("std"); const c = @import("c.zig"); const util = @import("util.zig"); -const DecorationManager = @import("DecorationManager.zig"); - -// TODO: this needs to listen for destroy and free nodes from the deco list -decoration_manager: *DecorationManager, wlr_xdg_toplevel_decoration: *c.wlr_xdg_toplevel_decoration_v1, listen_destroy: c.wl_listener, @@ -33,10 +29,8 @@ listen_request_mode: c.wl_listener, pub fn init( self: *Self, - decoration_manager: *DecorationManager, wlr_xdg_toplevel_decoration: *c.wlr_xdg_toplevel_decoration_v1, ) void { - self.decoration_manager = decoration_manager; self.wlr_xdg_toplevel_decoration = wlr_xdg_toplevel_decoration; self.listen_destroy.notify = handleDestroy; @@ -50,17 +44,13 @@ pub fn init( fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const self = @fieldParentPtr(Self, "listen_destroy", listener.?); - const node = @fieldParentPtr(std.SinglyLinkedList(Self).Node, "data", self); - - self.decoration_manager.decorations.remove(node); - util.gpa.destroy(node); + util.gpa.destroy(self); } fn handleRequestMode(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const self = @fieldParentPtr(Self, "listen_request_mode", listener.?); - // TODO: we might need to take this configure serial and do a transaction _ = c.wlr_xdg_toplevel_decoration_v1_set_mode( self.wlr_xdg_toplevel_decoration, - c.wlr_xdg_toplevel_decoration_v1_mode.WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE, + .WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE, ); } diff --git a/river/DecorationManager.zig b/river/DecorationManager.zig index 2eb1509..b44dcef 100644 --- a/river/DecorationManager.zig +++ b/river/DecorationManager.zig @@ -46,7 +46,9 @@ fn handleNewToplevelDecoration(listener: ?*c.wl_listener, data: ?*c_void) callco const self = @fieldParentPtr(Self, "listen_new_toplevel_decoration", listener.?); const wlr_xdg_toplevel_decoration = util.voidCast(c.wlr_xdg_toplevel_decoration_v1, data.?); - const node = self.decorations.allocateNode(util.gpa) catch unreachable; - node.data.init(self, wlr_xdg_toplevel_decoration); - self.decorations.prepend(node); + const decoration = util.gpa.create(Decoration) catch { + c.wl_resource_post_no_memory(wlr_xdg_toplevel_decoration.resource); + return; + }; + decoration.init(wlr_xdg_toplevel_decoration); } diff --git a/river/InputManager.zig b/river/InputManager.zig index 10293ea..80fd9e8 100644 --- a/river/InputManager.zig +++ b/river/InputManager.zig @@ -140,7 +140,5 @@ fn handleNewInput(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const device = util.voidCast(c.wlr_input_device, data.?); // TODO: suport multiple seats - if (self.seats.first) |seat_node| { - seat_node.data.addDevice(device) catch unreachable; - } + self.default_seat.addDevice(device); } diff --git a/river/LayerSurface.zig b/river/LayerSurface.zig index 97cf4bc..354173f 100644 --- a/river/LayerSurface.zig +++ b/river/LayerSurface.zig @@ -191,6 +191,9 @@ fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?); // This will free itself on destroy - var xdg_popup = util.gpa.create(XdgPopup) catch unreachable; + var xdg_popup = util.gpa.create(XdgPopup) catch { + c.wl_resource_post_no_memory(wlr_xdg_popup.resource); + return; + }; xdg_popup.init(self.output, &self.box, wlr_xdg_popup); } diff --git a/river/Root.zig b/river/Root.zig index 381ce89..b93ed8a 100644 --- a/river/Root.zig +++ b/river/Root.zig @@ -86,13 +86,19 @@ pub fn deinit(self: *Self) void { c.wlr_output_layout_destroy(self.wlr_output_layout); + // This literally cannot fail, but for some reason returns 0 if (c.wl_event_source_remove(self.transaction_timer) < 0) unreachable; } pub fn addOutput(self: *Self, wlr_output: *c.wlr_output) void { - // TODO: Handle failure - const node = self.outputs.allocateNode(util.gpa) catch unreachable; - node.data.init(self, wlr_output) catch unreachable; + const node = self.outputs.allocateNode(util.gpa) catch { + c.wlr_output_destroy(wlr_output); + return; + }; + node.data.init(self, wlr_output) catch { + c.wlr_output_destroy(wlr_output); + return; + }; self.outputs.append(node); // if we previously had no real outputs, move focus from the noop output diff --git a/river/Seat.zig b/river/Seat.zig index f1991f9..4850da7 100644 --- a/river/Seat.zig +++ b/river/Seat.zig @@ -157,9 +157,7 @@ pub fn focus(self: *Self, _view: ?*View) void { } } else { // The view is not in the stack, so allocate a new node and prepend it - const new_focus_node = util.gpa.create( - ViewStack(*View).Node, - ) catch unreachable; + const new_focus_node = util.gpa.create(ViewStack(*View).Node) catch return; new_focus_node.view = view_to_focus; self.focus_stack.push(new_focus_node); } @@ -305,30 +303,32 @@ pub fn handleMapping(self: *Self, keysym: c.xkb_keysym_t, modifiers: u32) bool { /// Add a newly created input device to the seat and update the reported /// capabilities. -pub fn addDevice(self: *Self, device: *c.wlr_input_device) !void { +pub fn addDevice(self: *Self, device: *c.wlr_input_device) void { switch (device.type) { - .WLR_INPUT_DEVICE_KEYBOARD => self.addKeyboard(device) catch unreachable, + .WLR_INPUT_DEVICE_KEYBOARD => self.addKeyboard(device) catch return, .WLR_INPUT_DEVICE_POINTER => self.addPointer(device), - else => {}, + else => return, } // We need to let the wlr_seat know what our capabilities are, which is // communiciated to the client. We always have a cursor, even if // there are no pointer devices, so we always include that capability. var caps = @intCast(u32, c.WL_SEAT_CAPABILITY_POINTER); - // if list not empty - if (self.keyboards.len > 0) { - caps |= @intCast(u32, c.WL_SEAT_CAPABILITY_KEYBOARD); - } + if (self.keyboards.len > 0) caps |= @intCast(u32, c.WL_SEAT_CAPABILITY_KEYBOARD); c.wlr_seat_set_capabilities(self.wlr_seat, caps); } fn addKeyboard(self: *Self, device: *c.wlr_input_device) !void { - c.wlr_seat_set_keyboard(self.wlr_seat, device); - - const node = try util.gpa.create(std.TailQueue(Keyboard).Node); - try node.data.init(self, device); + const node = try self.keyboards.allocateNode(util.gpa); + node.data.init(self, device) catch |err| { + switch (err) { + error.CreateXkbContextError => log.err(.keyboard, "Failed to create XKB context", .{}), + error.CreateXkbKeymapError => log.err(.keyboard, "Failed to create XKB keymap", .{}), + } + return; + }; self.keyboards.append(node); + c.wlr_seat_set_keyboard(self.wlr_seat, device); } fn addPointer(self: Self, device: *c.struct_wlr_input_device) void { diff --git a/river/Server.zig b/river/Server.zig index 90f6b19..0621a58 100644 --- a/river/Server.zig +++ b/river/Server.zig @@ -180,7 +180,10 @@ fn handleNewXdgSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) v // The View will add itself to the output's view stack on map const output = self.input_manager.default_seat.focused_output; - const node = util.gpa.create(ViewStack(View).Node) catch unreachable; + const node = util.gpa.create(ViewStack(View).Node) catch { + c.wl_resource_post_no_memory(wlr_xdg_surface.resource); + return; + }; node.view.init(output, output.current.tags, wlr_xdg_surface); } @@ -230,7 +233,10 @@ fn handleNewLayerSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) // The layer surface will add itself to the proper list of the output on map const output = util.voidCast(Output, wlr_layer_surface.output.*.data.?); - const node = util.gpa.create(std.TailQueue(LayerSurface).Node) catch unreachable; + const node = util.gpa.create(std.TailQueue(LayerSurface).Node) catch { + c.wl_resource_post_no_memory(wlr_layer_surface.resource); + return; + }; node.data.init(output, wlr_layer_surface); } @@ -242,7 +248,7 @@ fn handleNewXwaylandSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv( log.debug(.server, "new unmanaged xwayland surface", .{}); // The unmanged surface will add itself to the list of unmanaged views // in Root when it is mapped. - const node = util.gpa.create(std.TailQueue(XwaylandUnmanaged).Node) catch unreachable; + const node = util.gpa.create(std.TailQueue(XwaylandUnmanaged).Node) catch return; node.data.init(&self.root, wlr_xwayland_surface); return; } @@ -255,6 +261,6 @@ fn handleNewXwaylandSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv( // The View will add itself to the output's view stack on map const output = self.input_manager.default_seat.focused_output; - const node = util.gpa.create(ViewStack(View).Node) catch unreachable; + const node = util.gpa.create(ViewStack(View).Node) catch return; node.view.init(output, output.current.tags, wlr_xwayland_surface); } diff --git a/river/XdgPopup.zig b/river/XdgPopup.zig index b4e50cd..b966a45 100644 --- a/river/XdgPopup.zig +++ b/river/XdgPopup.zig @@ -76,6 +76,9 @@ fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?); // This will free itself on destroy - var xdg_popup = util.gpa.create(Self) catch unreachable; + var xdg_popup = util.gpa.create(Self) catch { + c.wl_resource_post_no_memory(wlr_xdg_popup.resource); + return; + }; xdg_popup.init(self.output, self.parent_box, wlr_xdg_popup); } diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index b818bbb..2ef46d3 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -253,7 +253,10 @@ fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?); // This will free itself on destroy - var xdg_popup = util.gpa.create(XdgPopup) catch unreachable; + var xdg_popup = util.gpa.create(XdgPopup) catch { + c.wl_resource_post_no_memory(wlr_xdg_popup.resource); + return; + }; xdg_popup.init(self.view.output, &self.view.current.box, wlr_xdg_popup); }