1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 02:17:35 +00:00

Kernel+LibC: Allow clock_gettime() to run without syscalls

This patch adds a vDSO-like mechanism for exposing the current time as
an array of per-clock-source timestamps.

LibC's clock_gettime() calls sys$map_time_page() to map the kernel's
"time page" into the process address space (at a random address, ofc.)
This is only done on first call, and from then on the timestamps are
fetched from the time page.

This first patch only adds support for CLOCK_REALTIME, but eventually
we should be able to support all clock sources this way and get rid of
sys$clock_gettime() in the kernel entirely. :^)

Accesses are synchronized using two atomic integers that are incremented
at the start and finish of the kernel's time page update cycle.
This commit is contained in:
Andreas Kling 2021-08-10 13:44:01 +02:00
parent f02d73db4d
commit fdfc66db61
7 changed files with 117 additions and 0 deletions

View file

@ -7,6 +7,7 @@
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <AK/Time.h>
#include <Kernel/API/TimePage.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
@ -362,8 +363,39 @@ clock_t clock()
return tms.tms_utime + tms.tms_stime;
}
static Kernel::TimePage* get_kernel_time_page()
{
static Kernel::TimePage* s_kernel_time_page;
// FIXME: Thread safety
if (!s_kernel_time_page) {
auto rc = syscall(SC_map_time_page);
if ((int)rc < 0 && (int)rc > -EMAXERRNO) {
errno = -(int)rc;
return nullptr;
}
s_kernel_time_page = (Kernel::TimePage*)rc;
}
return s_kernel_time_page;
}
int clock_gettime(clockid_t clock_id, struct timespec* ts)
{
if (Kernel::time_page_supports(clock_id)) {
if (!ts) {
errno = EFAULT;
return -1;
}
if (auto* kernel_time_page = get_kernel_time_page()) {
u32 update_iteration;
do {
update_iteration = AK::atomic_load(&kernel_time_page->update1, AK::memory_order_acquire);
*ts = kernel_time_page->clocks[clock_id];
} while (update_iteration != AK::atomic_load(&kernel_time_page->update2, AK::memory_order_acquire));
return 0;
}
}
int rc = syscall(SC_clock_gettime, clock_id, ts);
__RETURN_WITH_ERRNO(rc, rc, -1);
}