mirror of
https://github.com/RGBCube/serenity
synced 2025-05-16 07:04:58 +00:00
Kernel+LibC: Add adjtime(2)
Most systems (Linux, OpenBSD) adjust 0.5 ms per second, or 0.5 us per 1 ms tick. That is, the clock is sped up or slowed down by at most 0.05%. This means adjusting the clock by 1 s takes 2000 s, and the clock an be adjusted by at most 1.8 s per hour. FreeBSD adjusts 5 ms per second if the remaining time adjustment is >= 1 s (0.5%) , else it adjusts by 0.5 ms as well. This allows adjusting by (almost) 18 s per hour. Since Serenity OS can lose more than 22 s per hour (#3429), this picks an adjustment rate up to 1% for now. This allows us to adjust up to 36s per hour, which should be sufficient to adjust the clock fast enough to keep up with how much time the clock currently loses. Once we have a fancier NTP implementation that can adjust tick rate in addition to offset, we can think about reducing this. adjtime is a bit old-school and most current POSIX-y OSs instead implement adjtimex/ntp_adjtime, but a) we have to start somewhere b) ntp_adjtime() is a fairly gnarly API. OpenBSD's adjfreq looks like it might provide similar functionality with a nicer API. But before worrying about all this, it's probably a good idea to get to a place where the kernel APIs are (barely) good enough so that we can write an ntp service, and once we have that we should write a way to automatically evaluate how well it keeps the time adjusted, and only then should we add improvements ot the adjustment mechanism.
This commit is contained in:
parent
28abfd6290
commit
323e727a4c
8 changed files with 94 additions and 2 deletions
|
@ -25,6 +25,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Singleton.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Time.h>
|
||||
#include <Kernel/ACPI/Parser.h>
|
||||
#include <Kernel/CommandLine.h>
|
||||
|
@ -59,6 +60,7 @@ void TimeManagement::set_epoch_time(timespec ts)
|
|||
{
|
||||
InterruptDisabler disabler;
|
||||
m_epoch_time = ts;
|
||||
m_remaining_epoch_time_adjustment = { 0, 0 };
|
||||
}
|
||||
|
||||
timespec TimeManagement::epoch_time() const
|
||||
|
@ -256,7 +258,21 @@ void TimeManagement::increment_time_since_boot(const RegisterState&)
|
|||
{
|
||||
ASSERT(!m_time_keeper_timer.is_null());
|
||||
|
||||
timespec epoch_tick = { .tv_sec = 0, .tv_nsec = 1'000'000 }; // FIXME: Don't assume that one tick is 1 ms.
|
||||
// Compute time adjustment for adjtime. Let the clock run up to 1% fast or slow.
|
||||
// That way, adjtime can adjust up to 36 seconds per hour, without time getting very jumpy.
|
||||
// Once we have a smarter NTP service that also adjusts the frequency instead of just slewing time, maybe we can lower this.
|
||||
constexpr long NanosPerTick = 1'000'000; // FIXME: Don't assume that one tick is 1 ms.
|
||||
constexpr time_t MaxSlewNanos = NanosPerTick / 100;
|
||||
static_assert(MaxSlewNanos < NanosPerTick);
|
||||
|
||||
// Clamp twice, to make sure intermediate fits into a long.
|
||||
long slew_nanos = clamp(clamp(m_remaining_epoch_time_adjustment.tv_sec, (time_t)-1, (time_t)1) * 1'000'000'000 + m_remaining_epoch_time_adjustment.tv_nsec, -MaxSlewNanos, MaxSlewNanos);
|
||||
timespec slew_nanos_ts;
|
||||
timespec_sub({ 0, slew_nanos }, { 0, 0 }, slew_nanos_ts); // Normalize tv_nsec to be positive.
|
||||
timespec_sub(m_remaining_epoch_time_adjustment, slew_nanos_ts, m_remaining_epoch_time_adjustment);
|
||||
|
||||
timespec epoch_tick = { .tv_sec = 0, .tv_nsec = NanosPerTick };
|
||||
epoch_tick.tv_nsec += slew_nanos; // No need for timespec_add(), guaranteed to be in range.
|
||||
timespec_add(m_epoch_time, epoch_tick, m_epoch_time);
|
||||
|
||||
if (++m_ticks_this_second >= m_time_keeper_timer->ticks_per_second()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue