diff options
| author | Mitchell Hashimoto <mitchell.hashimoto@gmail.com> | 2022-11-04 20:27:48 -0700 |
|---|---|---|
| committer | Mitchell Hashimoto <mitchell.hashimoto@gmail.com> | 2022-11-05 19:31:02 -0700 |
| commit | b100406a6eaaaf6f92b0711141102e03f8f103bc (patch) | |
| tree | 6f2dc84169451ebe84af1ac8bf1415ce48666d22 /src/termio/Thread.zig | |
| parent | a8e7c520414be26a1ee424c3fd77561cd5ec8dc7 (diff) | |
termio: start the thread mailbox, hook up resize
Diffstat (limited to 'src/termio/Thread.zig')
| -rw-r--r-- | src/termio/Thread.zig | 50 |
1 files changed, 44 insertions, 6 deletions
diff --git a/src/termio/Thread.zig b/src/termio/Thread.zig index 9e81aa482..12949edcb 100644 --- a/src/termio/Thread.zig +++ b/src/termio/Thread.zig @@ -6,10 +6,16 @@ const std = @import("std"); const builtin = @import("builtin"); const libuv = @import("libuv"); const termio = @import("../termio.zig"); +const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue; const Allocator = std.mem.Allocator; const log = std.log.scoped(.io_thread); +/// The type used for sending messages to the IO thread. For now this is +/// hardcoded with a capacity. We can make this a comptime parameter in +/// the future if we want it configurable. +const Mailbox = BlockingQueue(termio.message.IO, 64); + /// The main event loop for the thread. The user data of this loop /// is always the allocator used to create the loop. This is a convenience /// so that users of the loop always have an allocator. @@ -24,6 +30,10 @@ stop: libuv.Async, /// The underlying IO implementation. impl: *termio.Impl, +/// The mailbox that can be used to send this thread messages. Note +/// this is a blocking queue so if it is full you will get errors (or block). +mailbox: *Mailbox, + /// Initialize the thread. This does not START the thread. This only sets /// up all the internal state necessary prior to starting the thread. It /// is up to the caller to start the thread with the threadMain entrypoint. @@ -60,11 +70,16 @@ pub fn init( } }).callback); + // The mailbox for messaging this thread + var mailbox = try Mailbox.create(alloc); + errdefer mailbox.destroy(alloc); + return Thread{ .loop = loop, .wakeup = wakeup_h, .stop = stop_h, .impl = impl, + .mailbox = mailbox, }; } @@ -95,6 +110,9 @@ pub fn deinit(self: *Thread) void { _ = self.loop.run(.default) catch |err| log.err("error finalizing event loop: {}", .{err}); + // Nothing can possibly access the mailbox anymore, destroy it. + self.mailbox.destroy(alloc); + // Dealloc our allocator copy alloc.destroy(alloc_ptr); @@ -127,13 +145,33 @@ fn threadMain_(self: *Thread) !void { _ = try self.loop.run(.default); } +/// Drain the mailbox, handling all the messages in our terminal implementation. +fn drainMailbox(self: *Thread) !void { + // This holds the mailbox lock for the duration of the drain. The + // expectation is that all our message handlers will be non-blocking + // ENOUGH to not mess up throughput on producers. + var drain = self.mailbox.drain(); + defer drain.deinit(); + + while (drain.next()) |message| { + log.debug("mailbox message={}", .{message}); + switch (message) { + .resize => |v| try self.impl.resize(v.grid_size, v.screen_size), + } + } +} + fn wakeupCallback(h: *libuv.Async) void { - _ = h; - // const t = h.getData(Thread) orelse { - // // This shouldn't happen so we log it. - // log.warn("render callback fired without data set", .{}); - // return; - // }; + const t = h.getData(Thread) orelse { + // This shouldn't happen so we log it. + log.warn("wakeup callback fired without data set", .{}); + return; + }; + + // When we wake up, we check the mailbox. Mailbox producers should + // wake up our thread after publishing. + t.drainMailbox() catch |err| + log.err("error draining mailbox err={}", .{err}); } fn stopCallback(h: *libuv.Async) void { |
