fully integrate libuv, no crash on close

This commit is contained in:
Mitchell Hashimoto
2022-04-22 12:11:53 -07:00
parent ccf95d823e
commit a57f4e76f1
2 changed files with 24 additions and 14 deletions

View File

@ -57,15 +57,14 @@ pub fn run(self: App) !void {
}).callback); }).callback);
defer embed.deinit(self.alloc); defer embed.deinit(self.alloc);
try embed.start(); 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); var timer = try libuv.Timer.init(self.alloc, self.loop);
defer timer.deinit(self.alloc); defer timer.deinit(self.alloc);
try timer.start((struct { try timer.start((struct {
fn callback(_: libuv.Timer) void { fn callback(_: libuv.Timer) void {}
log.info("timer tick", .{});
}
}).callback, 5000, 5000); }).callback, 5000, 5000);
while (!self.window.shouldClose()) { while (!self.window.shouldClose()) {
@ -79,5 +78,13 @@ pub fn run(self: App) !void {
try embed.loopRun(); 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();
} }

View File

@ -36,7 +36,6 @@ pub fn init(alloc: Allocator, loop: Loop, callback: fn () void) !Embed {
/// Deinit the embed struct. This will not automatically terminate /// Deinit the embed struct. This will not automatically terminate
/// the embed thread. You must call stop manually. /// the embed thread. You must call stop manually.
pub fn deinit(self: *Embed, alloc: Allocator) void { pub fn deinit(self: *Embed, alloc: Allocator) void {
std.debug.assert(self.thread == null);
self.sem.deinit(alloc); self.sem.deinit(alloc);
self.* = undefined; self.* = undefined;
} }
@ -48,18 +47,22 @@ pub fn start(self: *Embed) !void {
} }
/// Stop stops the embed thread and blocks until the thread joins. /// Stop stops the embed thread and blocks until the thread joins.
pub fn stop(self: *Embed) !void { pub fn stop(self: *Embed) void {
var thread = self.thread orelse return; if (self.thread == null) return;
// Mark that we want to terminate // Mark that we want to terminate
self.terminate.store(true, .SeqCst); self.terminate.store(true, .SeqCst);
// Post to the semaphore to ensure that any waits are processed. // Post to the semaphore to ensure that any waits are processed.
self.sem.post(); self.sem.post();
}
// Wait /// Wait for the thread backing the embedding to end.
try thread.join(); pub fn join(self: *Embed) !void {
self.thread = null; if (self.thread) |*thr| {
try thr.join();
self.thread = null;
}
} }
/// loopRun runs the next tick of the libuv event loop. This should be /// 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) { switch (builtin.os.tag) {
// epoll // epoll
.linux => { .linux => {
std.log.info("FOO {} {}", .{ fd, timeout });
var ev: [1]std.os.linux.epoll_event = undefined; var ev: [1]std.os.linux.epoll_event = undefined;
while (std.os.epoll_wait(fd, &ev, timeout) == -1) {} 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. // This just tests that the thread can start and then stop.
// It doesn't do much else at the moment // It doesn't do much else at the moment
try embed.start(); try embed.start();
try embed.stop(); embed.stop();
try embed.join();
} }