From 797da2f7379f38eb951906829b054c898690ac52 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 2 Jan 2024 12:35:31 -0800 Subject: [PATCH] termio/exec: avoid potential deadlock with surface message Fixes #1198 This adds a fix similar to what we discovered with termio messages: we attempt to send a surface message but if the queue is full we unlock the terminal state and try again waiting forever. In all cases, its safe to unlock the mutex while sending the message, no scenario we send a surface message requires this lock to be held. --- src/termio/Exec.zig | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 16c25eb6b..be8a6678f 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -1695,6 +1695,19 @@ const StreamHandler = struct { try self.ev.queueRender(); } + inline fn surfaceMessageWriter( + self: *StreamHandler, + msg: apprt.surface.Message, + ) void { + // See messageWriter which has similar logic and explains why + // we may have to do this. + if (self.ev.surface_mailbox.push(msg, .{ .instant = {} }) == 0) { + self.ev.renderer_state.mutex.unlock(); + defer self.ev.renderer_state.mutex.lock(); + _ = self.ev.surface_mailbox.push(msg, .{ .forever = {} }); + } + } + inline fn messageWriter(self: *StreamHandler, msg: termio.Message) void { // Try to write to the mailbox with an instant timeout. This is the // fast path because we can queue without a lock. @@ -2487,10 +2500,7 @@ const StreamHandler = struct { // Mark that we've seen a title self.ev.seen_title = true; - - _ = self.ev.surface_mailbox.push(.{ - .set_title = buf, - }, .{ .forever = {} }); + self.surfaceMessageWriter(.{ .set_title = buf }); } pub fn setMouseShape( @@ -2502,9 +2512,7 @@ const StreamHandler = struct { if (self.terminal.mouse_shape == shape) return; self.terminal.mouse_shape = shape; - _ = self.ev.surface_mailbox.push(.{ - .set_mouse_shape = shape, - }, .{ .forever = {} }); + self.surfaceMessageWriter(.{ .set_mouse_shape = shape }); } pub fn clipboardContents(self: *StreamHandler, kind: u8, data: []const u8) !void { @@ -2521,14 +2529,12 @@ const StreamHandler = struct { // Get clipboard contents if (data.len == 1 and data[0] == '?') { - _ = self.ev.surface_mailbox.push(.{ - .clipboard_read = clipboard_type, - }, .{ .forever = {} }); + self.surfaceMessageWriter(.{ .clipboard_read = clipboard_type }); return; } // Write clipboard contents - _ = self.ev.surface_mailbox.push(.{ + self.surfaceMessageWriter(.{ .clipboard_write = .{ .req = try apprt.surface.Message.WriteReq.init( self.alloc, @@ -2536,7 +2542,7 @@ const StreamHandler = struct { ), .clipboard_type = clipboard_type, }, - }, .{ .forever = {} }); + }); } pub fn promptStart(self: *StreamHandler, aid: ?[]const u8, redraw: bool) !void { @@ -2808,6 +2814,6 @@ const StreamHandler = struct { @memcpy(message.desktop_notification.body[0..body_len], body[0..body_len]); message.desktop_notification.body[body_len] = 0; - _ = self.ev.surface_mailbox.push(message, .{ .forever = {} }); + self.surfaceMessageWriter(message); } };