have to use an async handle to wake up event loop for max timer

This commit is contained in:
Mitchell Hashimoto
2022-04-29 19:24:17 -07:00
parent bb01357c42
commit 49f28b3bb7

View File

@ -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;
}