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);
|
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.
|
/// 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
|
/// 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 c = @import("c.zig");
|
||||||
|
|
||||||
|
const Loop = @import("Loop.zig");
|
||||||
|
|
||||||
/// Returns a struct that has all the shared handle functions for the
|
/// 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".
|
/// 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
|
/// 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);
|
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.
|
/// Sets handle->data to data.
|
||||||
pub fn setData(self: T, pointer: ?*anyopaque) void {
|
pub fn setData(self: T, pointer: ?*anyopaque) void {
|
||||||
c.uv_handle_set_data(
|
c.uv_handle_set_data(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub const Loop = @import("Loop.zig");
|
pub const Loop = @import("Loop.zig");
|
||||||
|
pub const Async = @import("Async.zig");
|
||||||
pub const Timer = @import("Timer.zig");
|
pub const Timer = @import("Timer.zig");
|
||||||
pub const Sem = @import("Sem.zig");
|
pub const Sem = @import("Sem.zig");
|
||||||
pub const Thread = @import("Thread.zig");
|
pub const Thread = @import("Thread.zig");
|
||||||
@ -7,7 +8,10 @@ pub const Error = @import("error.zig").Error;
|
|||||||
pub const Embed = @import("Embed.zig");
|
pub const Embed = @import("Embed.zig");
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
_ = @import("tests.zig");
|
||||||
|
|
||||||
_ = Loop;
|
_ = Loop;
|
||||||
|
_ = Async;
|
||||||
_ = Timer;
|
_ = Timer;
|
||||||
_ = Sem;
|
_ = Sem;
|
||||||
_ = Thread;
|
_ = 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