diff --git a/src/max_timer.zig b/src/max_timer.zig index addaf389f..5c3061e1c 100644 --- a/src/max_timer.zig +++ b/src/max_timer.zig @@ -25,6 +25,10 @@ pub fn MaxTimer(comptime cb: fn (*libuv.Timer) void) type { /// The last time this timer ran. last: u64 = 0, + /// This handle is used to wake up the event loop when the timer + /// is restarted. + async_h: libuv.Async, + pub fn init( loop: libuv.Loop, data: ?*anyopaque, @@ -35,6 +39,13 @@ pub fn MaxTimer(comptime cb: fn (*libuv.Timer) void) type { var timer = try libuv.Timer.init(alloc, loop); timer.setData(data); + // The async handle is used to wake up the event loop. This is + // necessary since stop/starting a timer doesn't trigger the + // poll on the backend fd. + var async_h = try libuv.Async.init(alloc, loop, (struct { + fn callback(_: *libuv.Async) void {} + }).callback); + // The maximum time can't be less than the interval otherwise this // will just constantly fire. if (max < min) return error.MaxShorterThanTimer; @@ -42,17 +53,24 @@ pub fn MaxTimer(comptime cb: fn (*libuv.Timer) void) type { .timer = timer, .min = min, .max = max, + .async_h = async_h, }; } pub fn deinit(self: *Self) void { + self.async_h.close((struct { + fn callback(h: *libuv.Async) void { + const alloc = h.loop().getData(Allocator).?.*; + h.deinit(alloc); + } + }).callback); + self.timer.close((struct { fn callback(t: *libuv.Timer) void { const alloc = t.loop().getData(Allocator).?.*; t.deinit(alloc); } }).callback); - self.* = undefined; } /// This should be called from the callback to update the last called time. @@ -70,6 +88,10 @@ pub fn MaxTimer(comptime cb: fn (*libuv.Timer) void) type { // a tick as soon as possible. if (!try self.timer.isActive()) { try self.timer.start(cb, self.min, self.min); + + // We have to send an async message to wake up the + // event loop. Starting a timer doesn't write to the fd. + try self.async_h.send(); return; }