1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:38:11 +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

@ -145,6 +145,9 @@ UNMAP_AFTER_INIT void TimeManagement::initialize(u32 cpu)
dmesgln("Time: Using APIC timer as system timer");
s_the->set_system_timer(*apic_timer);
}
s_the->m_time_page_region = MM.allocate_kernel_region(PAGE_SIZE, "Time page"sv, Memory::Region::Access::ReadWrite, AllocationStrategy::AllocateNow);
VERIFY(s_the->m_time_page_region);
} else {
VERIFY(s_the.is_initialized());
if (auto* apic_timer = APIC::the().get_timer()) {
@ -359,6 +362,9 @@ void TimeManagement::increment_time_since_boot_hpet()
m_ticks_this_second = ticks_this_second;
// TODO: Apply m_remaining_epoch_time_adjustment
timespec_add(m_epoch_time, { (time_t)(delta_ns / 1000000000), (long)(delta_ns % 1000000000) }, m_epoch_time);
update_time_page();
m_update2.store(update_iteration + 1, AK::MemoryOrder::memory_order_release);
}
@ -389,6 +395,8 @@ void TimeManagement::increment_time_since_boot()
++m_seconds_since_boot;
m_ticks_this_second = 0;
}
update_time_page();
m_update2.store(update_iteration + 1, AK::MemoryOrder::memory_order_release);
}
@ -419,4 +427,22 @@ bool TimeManagement::disable_profile_timer()
return true;
}
void TimeManagement::update_time_page()
{
auto* page = time_page();
u32 update_iteration = AK::atomic_fetch_add(&page->update1, 1u, AK::MemoryOrder::memory_order_acquire);
page->clocks[CLOCK_REALTIME] = m_epoch_time;
AK::atomic_store(&page->update2, update_iteration + 1u, AK::MemoryOrder::memory_order_release);
}
TimePage* TimeManagement::time_page()
{
return static_cast<TimePage*>((void*)m_time_page_region->vaddr().as_ptr());
}
Memory::VMObject& TimeManagement::time_page_vmobject()
{
return m_time_page_region->vmobject();
}
}