From 8a57d8a9b755ffb83aedb350dfc38745fc59e2e7 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 16 Nov 2023 21:58:45 +0100 Subject: [PATCH] libos: Use setitimer() for millisecond precision --- apps/clock.cpp | 2 +- libos/include/os/EventLoop.h | 4 ++-- libos/src/EventLoop.cpp | 27 +++++++++++++++++++++++---- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/apps/clock.cpp b/apps/clock.cpp index b63b3dae..080958b3 100644 --- a/apps/clock.cpp +++ b/apps/clock.cpp @@ -14,7 +14,7 @@ void update_time() g_label->set_text(StringView { buf }); - os::EventLoop::the().register_timer(1, update_time); + os::EventLoop::the().register_timer(1000, update_time); ui::App::the().main_window()->draw(); } diff --git a/libos/include/os/EventLoop.h b/libos/include/os/EventLoop.h index ea56c2b4..6eb6a9e5 100644 --- a/libos/include/os/EventLoop.h +++ b/libos/include/os/EventLoop.h @@ -64,11 +64,11 @@ namespace os /** * @brief Register a function to be called in a certain amount of time. * - * @param seconds The number of seconds to wait before invoking the function. + * @param milliseconds The number of milliseconds to wait before invoking the function. * @param callback The function to call when the time is up. * @return Result Whether the operation succeeded. */ - Result register_timer(unsigned int seconds, Action&& callback); + Result register_timer(long milliseconds, Action&& callback); /** * @brief Run the event loop until it is asked to quit. diff --git a/libos/src/EventLoop.cpp b/libos/src/EventLoop.cpp index 5fe31d5d..c699c1c6 100644 --- a/libos/src/EventLoop.cpp +++ b/libos/src/EventLoop.cpp @@ -12,11 +12,27 @@ #include #include #include +#include #include #include static os::EventLoop* s_the = nullptr; +static void alarm_milliseconds(long target) +{ + struct itimerval itimer; + memset(&itimer.it_interval, 0, sizeof(itimer.it_interval)); + itimer.it_value = { .tv_sec = target / 1000, .tv_usec = (target % 1000) * 1000 }; + setitimer(ITIMER_REAL, &itimer, nullptr); +} + +static long get_monotonic_time_in_milliseconds() +{ + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + return time.tv_sec * 1000 + time.tv_nsec / 1'000'000; +} + namespace os { EventLoop::EventLoop() @@ -62,9 +78,9 @@ namespace os return {}; } - Result EventLoop::register_timer(unsigned int seconds, Action&& callback) + Result EventLoop::register_timer(long milliseconds, Action&& callback) { - long target = time(NULL) + seconds; + long target = get_monotonic_time_in_milliseconds() + milliseconds; auto* timer = TRY(make()); timer->target = target; @@ -83,7 +99,7 @@ namespace os if (m_timer_queue.first().value_or(nullptr) == next) { - alarm(seconds); + alarm_milliseconds(milliseconds); m_timer_queue.prepend(timer); } else if (next == nullptr) { m_timer_queue.append(timer); } @@ -158,7 +174,10 @@ namespace os auto timer = queue.remove(queue.expect_first()); auto first = queue.first(); - if (first.has_value()) { alarm((unsigned int)(first.value()->target - time(NULL))); } + if (first.has_value()) + { + alarm((unsigned int)(first.value()->target - get_monotonic_time_in_milliseconds())); + } timer->action(); delete timer;