mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
libuv: Async
This commit is contained in:
54
src/libuv/Async.zig
Normal file
54
src/libuv/Async.zig
Normal file
@ -0,0 +1,54 @@
|
||||
//! Async handles allow the user to “wakeup” the event loop and get a callback
|
||||
//! called from another thread.
|
||||
const Async = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const testing = std.testing;
|
||||
const c = @import("c.zig");
|
||||
const errors = @import("error.zig");
|
||||
const Loop = @import("Loop.zig");
|
||||
const Handle = @import("handle.zig").Handle;
|
||||
|
||||
handle: *c.uv_async_t,
|
||||
|
||||
pub usingnamespace Handle(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});
|
||||
}
|
||||
};
|
||||
|
||||
try errors.convertError(c.uv_async_init(loop.loop, handle, Wrapper.callback));
|
||||
return Async{ .handle = handle };
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Async, alloc: Allocator) void {
|
||||
alloc.destroy(self.handle);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
/// Wake up the event loop and call the async handle’s callback.
|
||||
pub fn send(self: Async) !void {
|
||||
try errors.convertError(c.uv_async_send(self.handle));
|
||||
}
|
||||
|
||||
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 {
|
||||
v.close(null);
|
||||
}
|
||||
}).callback);
|
||||
defer h.deinit(testing.allocator);
|
||||
|
||||
try h.send();
|
||||
_ = try loop.run(.default);
|
||||
}
|
@ -46,6 +46,13 @@ pub fn run(self: Loop, mode: RunMode) !u32 {
|
||||
return @intCast(u32, res);
|
||||
}
|
||||
|
||||
/// Stop the event loop, causing uv_run() to end as soon as possible. This
|
||||
/// will happen not sooner than the next loop iteration. If this function was
|
||||
/// called before blocking for i/o, the loop won’t block for i/o on this iteration.
|
||||
pub fn stop(self: Loop) void {
|
||||
c.uv_stop(self.loop);
|
||||
}
|
||||
|
||||
/// Get backend file descriptor. Only kqueue, epoll and event ports are supported.
|
||||
///
|
||||
/// This can be used in conjunction with uv_run(loop, UV_RUN_NOWAIT) to poll
|
||||
|
@ -1,5 +1,7 @@
|
||||
const c = @import("c.zig");
|
||||
|
||||
const Loop = @import("Loop.zig");
|
||||
|
||||
/// Returns a struct that has all the shared handle functions for the
|
||||
/// given handle type T. The type T must have a field named "handle".
|
||||
/// This is expected to be used with usingnamespace to add the shared
|
||||
@ -40,6 +42,12 @@ pub fn Handle(comptime T: type) type {
|
||||
c.uv_close(@ptrCast(*c.uv_handle_t, self.handle), cbParam);
|
||||
}
|
||||
|
||||
/// Loop returns the loop that this handle is a part of.
|
||||
pub fn loop(self: T) Loop {
|
||||
const handle = @ptrCast(*c.uv_handle_t, self.handle);
|
||||
return .{ .loop = c.uv_handle_get_loop(handle) };
|
||||
}
|
||||
|
||||
/// Sets handle->data to data.
|
||||
pub fn setData(self: T, pointer: ?*anyopaque) void {
|
||||
c.uv_handle_set_data(
|
||||
|
@ -1,4 +1,5 @@
|
||||
pub const Loop = @import("Loop.zig");
|
||||
pub const Async = @import("Async.zig");
|
||||
pub const Timer = @import("Timer.zig");
|
||||
pub const Sem = @import("Sem.zig");
|
||||
pub const Thread = @import("Thread.zig");
|
||||
@ -7,7 +8,10 @@ pub const Error = @import("error.zig").Error;
|
||||
pub const Embed = @import("Embed.zig");
|
||||
|
||||
test {
|
||||
_ = @import("tests.zig");
|
||||
|
||||
_ = Loop;
|
||||
_ = Async;
|
||||
_ = Timer;
|
||||
_ = Sem;
|
||||
_ = Thread;
|
||||
|
37
src/libuv/tests.zig
Normal file
37
src/libuv/tests.zig
Normal file
@ -0,0 +1,37 @@
|
||||
//! This file contains other behavior tests for the libuv integration.
|
||||
//! We trust that libuv works, but still test some behaviors to ensure
|
||||
//! that our wrappers around libuv are working as expected.
|
||||
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const libuv = @import("main.zig");
|
||||
|
||||
test "Async: cancel timer" {
|
||||
const alloc = testing.allocator;
|
||||
var loop = try libuv.Loop.init(alloc);
|
||||
defer loop.deinit(alloc);
|
||||
|
||||
var timer = try libuv.Timer.init(alloc, loop);
|
||||
defer timer.deinit(alloc);
|
||||
|
||||
// Start a timer with a long timeout. This will block our loop.
|
||||
try timer.start((struct {
|
||||
fn callback(_: libuv.Timer) void {}
|
||||
}).callback, 5000, 5000);
|
||||
|
||||
var async_handle = try libuv.Async.init(testing.allocator, loop, (struct {
|
||||
fn callback(v: libuv.Async) void {
|
||||
v.loop().stop();
|
||||
v.close(null);
|
||||
}
|
||||
}).callback);
|
||||
defer async_handle.deinit(testing.allocator);
|
||||
try async_handle.send();
|
||||
|
||||
// This run through the loop should exit because we called loop stop.
|
||||
_ = try loop.run(.default);
|
||||
|
||||
// We need to run the loop one more time to handle all our close callbacks.
|
||||
timer.close(null);
|
||||
_ = try loop.run(.default);
|
||||
}
|
Reference in New Issue
Block a user