mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 07:46:12 +03:00
libuv: Timers
This commit is contained in:
@ -30,6 +30,13 @@ pub fn deinit(self: *Loop, alloc: Allocator) void {
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
/// Returns true if the loop is still alive.
|
||||
pub fn alive(self: Loop) !bool {
|
||||
const res = c.uv_loop_alive(self.loop);
|
||||
try errors.convertError(res);
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
/// This function runs the event loop. See RunMode for mode documentation.
|
||||
///
|
||||
/// This is not reentrant. It must not be called from a callback.
|
||||
|
54
src/libuv/Timer.zig
Normal file
54
src/libuv/Timer.zig
Normal file
@ -0,0 +1,54 @@
|
||||
//! Timer handles are used to schedule callbacks to be called in the future.
|
||||
const Timer = @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_timer_t,
|
||||
|
||||
pub usingnamespace Handle(Timer);
|
||||
|
||||
pub fn init(alloc: Allocator, loop: Loop) !Timer {
|
||||
var timer = try alloc.create(c.uv_timer_t);
|
||||
errdefer alloc.destroy(timer);
|
||||
try errors.convertError(c.uv_timer_init(loop.loop, timer));
|
||||
return Timer{ .handle = timer };
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Timer, alloc: Allocator) void {
|
||||
alloc.destroy(self.handle);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
test "Timer" {
|
||||
var loop = try Loop.init(testing.allocator);
|
||||
defer loop.deinit(testing.allocator);
|
||||
var timer = try init(testing.allocator, loop);
|
||||
defer timer.deinit(testing.allocator);
|
||||
timer.close(null);
|
||||
_ = try loop.run(.default);
|
||||
}
|
||||
|
||||
test "Timer: close callback" {
|
||||
var loop = try Loop.init(testing.allocator);
|
||||
defer loop.deinit(testing.allocator);
|
||||
var timer = try init(testing.allocator, loop);
|
||||
defer timer.deinit(testing.allocator);
|
||||
|
||||
var data: u8 = 42;
|
||||
timer.setData(&data);
|
||||
timer.close((struct {
|
||||
fn callback(v: *Timer) void {
|
||||
var dataPtr = v.getData(u8).?;
|
||||
dataPtr.* = 24;
|
||||
}
|
||||
}).callback);
|
||||
_ = try loop.run(.default);
|
||||
|
||||
try testing.expectEqual(@as(u8, 24), data);
|
||||
}
|
60
src/libuv/handle.zig
Normal file
60
src/libuv/handle.zig
Normal file
@ -0,0 +1,60 @@
|
||||
const c = @import("c.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
|
||||
/// handler functions to other handle types.
|
||||
pub fn Handle(comptime T: type) type {
|
||||
// 1. T should be a struct
|
||||
// 2. First field should be the handle pointer
|
||||
const tInfo = @typeInfo(T).Struct;
|
||||
const HandleType = tInfo.fields[0].field_type;
|
||||
|
||||
return struct {
|
||||
// Request handle to be closed. close_cb will be called asynchronously
|
||||
// after this call. This MUST be called on each handle before memory
|
||||
// is released. Moreover, the memory can only be released in close_cb
|
||||
// or after it has returned.
|
||||
//
|
||||
// Handles that wrap file descriptors are closed immediately but
|
||||
// close_cb will still be deferred to the next iteration of the event
|
||||
// loop. It gives you a chance to free up any resources associated with
|
||||
// the handle.
|
||||
//
|
||||
// In-progress requests, like uv_connect_t or uv_write_t, are cancelled
|
||||
// and have their callbacks called asynchronously with status=UV_ECANCELED.
|
||||
pub fn close(self: *T, comptime cb: ?fn (*T) void) void {
|
||||
const cbParam = if (cb) |f|
|
||||
(struct {
|
||||
pub fn callback(handle: [*c]c.uv_handle_t) callconv(.C) void {
|
||||
// We get the raw handle, so we need to reconstruct
|
||||
// the T. This is mutable because a lot of the libuv APIs
|
||||
// are non-const but modifying it makes no sense.
|
||||
var param: T = .{ .handle = @ptrCast(HandleType, handle) };
|
||||
|
||||
@call(.{ .modifier = .always_inline }, f, .{¶m});
|
||||
}
|
||||
}).callback
|
||||
else
|
||||
null;
|
||||
|
||||
c.uv_close(@ptrCast(*c.uv_handle_t, self.handle), cbParam);
|
||||
}
|
||||
|
||||
/// Sets handle->data to data.
|
||||
pub fn setData(self: *T, pointer: ?*anyopaque) void {
|
||||
c.uv_handle_set_data(
|
||||
@ptrCast(*c.uv_handle_t, self.handle),
|
||||
pointer,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns handle->data.
|
||||
pub fn getData(self: *T, comptime DT: type) ?*DT {
|
||||
return if (c.uv_handle_get_data(@ptrCast(*c.uv_handle_t, self.handle))) |ptr|
|
||||
@ptrCast(?*DT, @alignCast(@alignOf(DT), ptr))
|
||||
else
|
||||
null;
|
||||
}
|
||||
};
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
const Loop = @import("Loop.zig");
|
||||
const Timer = @import("Timer.zig");
|
||||
const Sem = @import("Sem.zig");
|
||||
const Thread = @import("Thread.zig");
|
||||
const Error = @import("error.zig").Error;
|
||||
|
||||
test {
|
||||
_ = Loop;
|
||||
_ = Timer;
|
||||
_ = Sem;
|
||||
_ = Thread;
|
||||
_ = Error;
|
||||
|
Reference in New Issue
Block a user