mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
use async handles to more immediately exit the event loop
This commit is contained in:
32
src/App.zig
32
src/App.zig
@ -55,7 +55,8 @@ pub fn deinit(self: *App) void {
|
||||
// Run the loop one more time, because destroying our other things
|
||||
// like windows usually cancel all our event loop stuff and we need
|
||||
// one more run through to finalize all the closes.
|
||||
_ = self.loop.run(.default) catch unreachable;
|
||||
_ = self.loop.run(.default) catch |err|
|
||||
log.err("error finalizing event loop: {}", .{err});
|
||||
|
||||
// Dealloc our allocator copy
|
||||
self.alloc.destroy(self.loop.getData(Allocator).?);
|
||||
@ -76,13 +77,11 @@ pub fn run(self: App) !void {
|
||||
defer embed.deinit(self.alloc);
|
||||
try embed.start();
|
||||
|
||||
// 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);
|
||||
errdefer timer.deinit(self.alloc);
|
||||
try timer.start((struct {
|
||||
fn callback(_: *libuv.Timer) void {}
|
||||
}).callback, 5000, 5000);
|
||||
// This async handle is used to "wake up" the embed thread so we can
|
||||
// exit immediately once the windows want to close.
|
||||
var async_h = try libuv.Async.init(self.alloc, self.loop, (struct {
|
||||
fn callback(_: *libuv.Async) void {}
|
||||
}).callback);
|
||||
|
||||
while (!self.window.shouldClose()) {
|
||||
try self.window.run();
|
||||
@ -95,14 +94,19 @@ pub fn run(self: App) !void {
|
||||
try embed.loopRun();
|
||||
}
|
||||
|
||||
// Close our timer so that we can cleanly close the loop.
|
||||
timer.close((struct {
|
||||
fn callback(t: *libuv.Timer) void {
|
||||
const alloc = t.loop().getData(Allocator).?.*;
|
||||
t.deinit(alloc);
|
||||
// Notify the embed thread to stop. We do this before we send on the
|
||||
// async handle so that when the thread goes around it exits.
|
||||
embed.stop();
|
||||
|
||||
// Wake up the event loop and schedule our close.
|
||||
try async_h.send();
|
||||
async_h.close((struct {
|
||||
fn callback(h: *libuv.Async) void {
|
||||
const alloc = h.loop().getData(Allocator).?.*;
|
||||
h.deinit(alloc);
|
||||
}
|
||||
}).callback);
|
||||
|
||||
embed.stop();
|
||||
// Wait for the thread to end which should be almost instant.
|
||||
try embed.join();
|
||||
}
|
||||
|
@ -14,14 +14,14 @@ handle: *c.uv_async_t,
|
||||
|
||||
pub usingnamespace Handle(Async);
|
||||
|
||||
pub fn init(alloc: Allocator, loop: Loop, comptime cb: fn (Async) void) !Async {
|
||||
pub fn init(alloc: Allocator, loop: Loop, comptime cb: fn (*Async) void) !Async {
|
||||
var handle = try alloc.create(c.uv_async_t);
|
||||
errdefer alloc.destroy(handle);
|
||||
|
||||
const Wrapper = struct {
|
||||
pub fn callback(arg: [*c]c.uv_async_t) callconv(.C) void {
|
||||
const newSelf: Async = .{ .handle = arg };
|
||||
@call(.{ .modifier = .always_inline }, cb, .{newSelf});
|
||||
var newSelf: Async = .{ .handle = arg };
|
||||
@call(.{ .modifier = .always_inline }, cb, .{&newSelf});
|
||||
}
|
||||
};
|
||||
|
||||
@ -43,7 +43,7 @@ test "Async" {
|
||||
var loop = try Loop.init(testing.allocator);
|
||||
defer loop.deinit(testing.allocator);
|
||||
var h = try init(testing.allocator, loop, (struct {
|
||||
fn callback(v: Async) void {
|
||||
fn callback(v: *Async) void {
|
||||
v.close(null);
|
||||
}
|
||||
}).callback);
|
||||
|
@ -20,7 +20,7 @@ test "Async: cancel timer" {
|
||||
}).callback, 5000, 5000);
|
||||
|
||||
var async_handle = try libuv.Async.init(testing.allocator, loop, (struct {
|
||||
fn callback(v: libuv.Async) void {
|
||||
fn callback(v: *libuv.Async) void {
|
||||
v.loop().stop();
|
||||
v.close(null);
|
||||
}
|
||||
|
Reference in New Issue
Block a user