From a57f4e76f10b0312e31e50ac18d874103385fec8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 22 Apr 2022 12:11:53 -0700 Subject: [PATCH] fully integrate libuv, no crash on close --- src/App.zig | 19 +++++++++++++------ src/libuv/Embed.zig | 19 +++++++++++-------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/App.zig b/src/App.zig index 7adae511b..a6c71d0d0 100644 --- a/src/App.zig +++ b/src/App.zig @@ -57,15 +57,14 @@ pub fn run(self: App) !void { }).callback); defer embed.deinit(self.alloc); try embed.start(); - errdefer embed.stop() catch unreachable; + errdefer embed.stop(); - // We need at least one handle in the event loop at all times + // We need at least one handle in the event loop at all times so + // that the loop doesn't spin 100% CPU. var timer = try libuv.Timer.init(self.alloc, self.loop); defer timer.deinit(self.alloc); try timer.start((struct { - fn callback(_: libuv.Timer) void { - log.info("timer tick", .{}); - } + fn callback(_: libuv.Timer) void {} }).callback, 5000, 5000); while (!self.window.shouldClose()) { @@ -79,5 +78,13 @@ pub fn run(self: App) !void { try embed.loopRun(); } - try embed.stop(); + // CLose our timer so that we can cleanly close the loop. + timer.close(null); + _ = try self.loop.run(.default); + + // Notify the embedder to stop. We purposely do NOT wait for `join` + // here because handles with long timeouts may cause this to take a long + // time. We're exiting the app anyways if we're here so we let the OS + // clean up the threads. + embed.stop(); } diff --git a/src/libuv/Embed.zig b/src/libuv/Embed.zig index 5ac618658..6fd6552e1 100644 --- a/src/libuv/Embed.zig +++ b/src/libuv/Embed.zig @@ -36,7 +36,6 @@ pub fn init(alloc: Allocator, loop: Loop, callback: fn () void) !Embed { /// Deinit the embed struct. This will not automatically terminate /// the embed thread. You must call stop manually. pub fn deinit(self: *Embed, alloc: Allocator) void { - std.debug.assert(self.thread == null); self.sem.deinit(alloc); self.* = undefined; } @@ -48,18 +47,22 @@ pub fn start(self: *Embed) !void { } /// Stop stops the embed thread and blocks until the thread joins. -pub fn stop(self: *Embed) !void { - var thread = self.thread orelse return; +pub fn stop(self: *Embed) void { + if (self.thread == null) return; // Mark that we want to terminate self.terminate.store(true, .SeqCst); // Post to the semaphore to ensure that any waits are processed. self.sem.post(); +} - // Wait - try thread.join(); - self.thread = null; +/// Wait for the thread backing the embedding to end. +pub fn join(self: *Embed) !void { + if (self.thread) |*thr| { + try thr.join(); + self.thread = null; + } } /// loopRun runs the next tick of the libuv event loop. This should be @@ -77,7 +80,6 @@ fn threadMain(self: *Embed) void { switch (builtin.os.tag) { // epoll .linux => { - std.log.info("FOO {} {}", .{ fd, timeout }); var ev: [1]std.os.linux.epoll_event = undefined; while (std.os.epoll_wait(fd, &ev, timeout) == -1) {} }, @@ -105,5 +107,6 @@ test "Embed" { // This just tests that the thread can start and then stop. // It doesn't do much else at the moment try embed.start(); - try embed.stop(); + embed.stop(); + try embed.join(); }