From fd6583dac7371f14cb20ea0437699affa6184117 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 16 Dec 2022 18:04:16 +0100 Subject: [PATCH] Implement timers Implements: https://todo.sr.ht/~sircmpwn/hare-ev/9 --- cmd/timer/main.ha | 17 +++++++++++++++++ ev/+linux/file.ha | 5 +++++ ev/+linux/loop.ha | 4 +++- ev/+linux/timers.ha | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/cmd/timer/main.ha b/cmd/timer/main.ha new file mode 100644 index 0000000000000000000000000000000000000000..09867d076b3060be1f4e4eaaf3735d4c172d0374 --- /dev/null +++ b/cmd/timer/main.ha @@ -0,0 +1,17 @@ +use ev; +use log; +use time; + +export fn main() void = { + const loop = ev::newloop()!; + defer ev::finish(&loop); + + const timer = ev::newtimer(&loop, &expired, time::clock::MONOTONIC)!; + ev::timer_configure(timer, 1 * time::SECOND, 500 * time::MILLISECOND); + + for (ev::dispatch(&loop, -1)!) void; +}; + +fn expired(timer: *ev::file) void = { + log::println("timer expired"); +}; diff --git a/ev/+linux/file.ha b/ev/+linux/file.ha index 662cb7125ed10ba1c294afc35f96a95e54e5d181..e47dbf9e9e33859a394136bcccd42f35a75ed5b6 100644 --- a/ev/+linux/file.ha +++ b/ev/+linux/file.ha @@ -14,6 +14,7 @@ WRITABLE = 2 << 16, ACCEPT = 3 << 16, CONNECT = 4 << 16, SIGNAL = 5 << 16, + TIMER = 6 << 16, }; export type fflags = enum uint { @@ -140,6 +141,10 @@ if (file.op & op::CONNECT != 0) { events |= rt::EPOLLOUT; }; if (file.op & op::SIGNAL != 0) { + events |= rt::EPOLLIN; + }; + if (file.op & op::TIMER != 0) { + events &= ~rt::EPOLLONESHOT; events |= rt::EPOLLIN; }; diff --git a/ev/+linux/loop.ha b/ev/+linux/loop.ha index a5942b88e352f447018663c659f0f6bf748e3835..64a0dc35d6b12ff91ead51be9a45d11fc206cdc7 100644 --- a/ev/+linux/loop.ha +++ b/ev/+linux/loop.ha @@ -108,8 +108,10 @@ case op::CONNECT => connect_ready(file, ev); case op::SIGNAL => signal_ready(file, ev); + case op::TIMER => + timer_ready(file, ev); case => - yield; + assert(pending & ~(op::READV | op::WRITEV) == 0); }; }; diff --git a/ev/+linux/timers.ha b/ev/+linux/timers.ha new file mode 100644 index 0000000000000000000000000000000000000000..539c7484bf8a033f9c8cb50dcc0d01f9b8da5a85 --- /dev/null +++ b/ev/+linux/timers.ha @@ -0,0 +1,52 @@ +use errors; +use io; +use rt; +use time; + +// A callback which executes when a timer expires. +export type timercb = fn(file: *file) void; + +// Creates a new timer. By default, this timer never expires; configure it with +// [[timer_configure]]. +export fn newtimer( + loop: *loop, + cb: *timercb, + clock: time::clock, +) (*file | errors::error) = { + const fd = match (rt::timerfd_create(clock, rt::TFD_CLOEXEC)) { + case let fd: int => + yield fd: io::file; + case let errno: rt::errno => + return errors::errno(errno); + }; + const file = register(loop, fd)?; + file.op = op::TIMER; + file.cb = cb; + file_epoll_ctl(file); + return file; +}; + +// Starts a timer created with [[newtimer]] to expire after the given "delay" +// and indefinitely thereafter following each interval of "repeat". Setting both +// values to zero disarms the timer; setting either value non-zero arms the +// timer. +export fn timer_configure( + timer: *file, + delay: time::duration, + repeat: time::duration, +) void = { + let spec = rt::itimerspec { ... }; + time::duration_to_timespec(delay, &spec.it_value); + time::duration_to_timespec(repeat, &spec.it_interval); + rt::timerfd_settime(timer.fd, 0, &spec, null)!; +}; + +fn timer_ready(timer: *file, ev: *rt::epoll_event) void = { + assert(timer.op == op::TIMER); + let buf: [8]u8 = [0...]; + io::read(timer.fd, buf)!; + + assert(timer.cb != null); + const cb = timer.cb: *timercb; + cb(timer); +}; -- 2.48.1