From 94ff04b5361cba26b76be7caff1c3edb30b22dd3 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 22 Nov 2020 17:20:58 +0100 Subject: [PATCH] Kernel: Make CLOCK_MONOTONIC respect the system tick frequency The time returned by sys$clock_gettime() was not aligned with the delay calculations in sys$clock_nanosleep(). This patch fixes that by taking the system's ticks_per_second value into account in both functions. This patch also removes the need for Thread::sleep_until() and uses Thread::sleep() for both absolute and relative sleeps. This was causing the nesalizer emulator port to sleep for a negative amount of time at the end of each frame, making it run way too fast. --- Kernel/Syscalls/clock.cpp | 35 ++++++++++++++++++----------------- Kernel/Thread.cpp | 9 --------- Kernel/Thread.h | 1 - 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/Kernel/Syscalls/clock.cpp b/Kernel/Syscalls/clock.cpp index e7d40c5be3..97793219ad 100644 --- a/Kernel/Syscalls/clock.cpp +++ b/Kernel/Syscalls/clock.cpp @@ -37,10 +37,13 @@ int Process::sys$clock_gettime(clockid_t clock_id, Userspace user_ts) timespec ts = {}; switch (clock_id) { - case CLOCK_MONOTONIC: - ts.tv_sec = TimeManagement::the().seconds_since_boot(); - ts.tv_nsec = TimeManagement::the().ticks_this_second() * 1000000; + case CLOCK_MONOTONIC: { + auto ticks_per_second = TimeManagement::the().ticks_per_second(); + auto uptime = g_uptime; + ts.tv_sec = uptime / ticks_per_second; + ts.tv_nsec = (1000000000 * (uptime % ticks_per_second)) / ticks_per_second; break; + } case CLOCK_REALTIME: ts = TimeManagement::the().epoch_time(); break; @@ -88,26 +91,24 @@ int Process::sys$clock_nanosleep(Userspacesleep_until(time_to_wake); - } else { - u64 ticks_to_sleep = requested_sleep.tv_sec * TimeManagement::the().ticks_per_second(); - ticks_to_sleep += requested_sleep.tv_nsec * TimeManagement::the().ticks_per_second() / 1000000000; - if (!ticks_to_sleep) - return 0; - wakeup_time = Thread::current()->sleep(ticks_to_sleep); - } + u64 ticks_to_sleep = requested_sleep.tv_sec * ticks_per_second; + ticks_to_sleep += (requested_sleep.tv_nsec * ticks_per_second) / 1000000000; + if (is_absolute) + ticks_to_sleep -= g_uptime; + if (!ticks_to_sleep) + return 0; + u64 wakeup_time = Thread::current()->sleep(ticks_to_sleep); if (wakeup_time > g_uptime) { u64 ticks_left = wakeup_time - g_uptime; if (!is_absolute && params.remaining_sleep) { timespec remaining_sleep = {}; - remaining_sleep.tv_sec = ticks_left / TimeManagement::the().ticks_per_second(); - ticks_left -= remaining_sleep.tv_sec * TimeManagement::the().ticks_per_second(); - remaining_sleep.tv_nsec = ticks_left * 1000000000 / TimeManagement::the().ticks_per_second(); + remaining_sleep.tv_sec = ticks_left / ticks_per_second; + ticks_left -= remaining_sleep.tv_sec * ticks_per_second; + remaining_sleep.tv_nsec = (ticks_left * 1000000000) / ticks_per_second; if (!copy_to_user(params.remaining_sleep, &remaining_sleep)) return -EFAULT; } diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 7de2263303..201e9e5446 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -258,15 +258,6 @@ u64 Thread::sleep(u64 ticks) return wakeup_time; } -u64 Thread::sleep_until(u64 wakeup_time) -{ - ASSERT(state() == Thread::Running); - auto ret = Thread::current()->block(nullptr, wakeup_time); - if (wakeup_time > g_uptime) - ASSERT(ret.was_interrupted()); - return wakeup_time; -} - const char* Thread::state_string() const { switch (state()) { diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 2c482e1f74..96dc5b2aa2 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -377,7 +377,6 @@ public: size_t thread_specific_region_size() const { return m_thread_specific_region_size; } u64 sleep(u64 ticks); - u64 sleep_until(u64 wakeup_time); class BlockResult { public: