1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 19:47:42 +00:00

Kernel: Let TimeManagement keep epoch time as timespec

Previously, it was kept as just a time_t and the sub-second
offset was inferred from the monotonic clock. This means that
sub-second time adjustments were ignored.

Now that `ntpquery -s` can pass in a time with sub-second
precision, it makes sense to keep time at that granularity
in the kernel.

After this, `ntpquery -s` immediately followed by `ntpquery` shows
an offset of 0.02s (that is, on the order of network roundtrip time)
instead of up to 0.75s previously.
This commit is contained in:
Nico Weber 2020-09-06 19:52:24 -04:00 committed by Andreas Kling
parent 4ac5cc2461
commit e8131f503d
3 changed files with 22 additions and 15 deletions

View file

@ -43,8 +43,7 @@ int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
ts.tv_nsec = TimeManagement::the().ticks_this_second() * 1000000; ts.tv_nsec = TimeManagement::the().ticks_this_second() * 1000000;
break; break;
case CLOCK_REALTIME: case CLOCK_REALTIME:
ts.tv_sec = TimeManagement::the().epoch_time(); ts = TimeManagement::the().epoch_time();
ts.tv_nsec = TimeManagement::the().ticks_this_second() * 1000000;
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -67,7 +66,7 @@ int Process::sys$clock_settime(clockid_t clock_id, Userspace<const timespec*> us
switch (clock_id) { switch (clock_id) {
case CLOCK_REALTIME: case CLOCK_REALTIME:
TimeManagement::the().set_epoch_time(ts.tv_sec); TimeManagement::the().set_epoch_time(ts);
break; break;
default: default:
return -EINVAL; return -EINVAL;

View file

@ -25,6 +25,7 @@
*/ */
#include <AK/Singleton.h> #include <AK/Singleton.h>
#include <AK/Time.h>
#include <Kernel/ACPI/Parser.h> #include <Kernel/ACPI/Parser.h>
#include <Kernel/CommandLine.h> #include <Kernel/CommandLine.h>
#include <Kernel/Scheduler.h> #include <Kernel/Scheduler.h>
@ -52,15 +53,20 @@ bool TimeManagement::is_system_timer(const HardwareTimer& timer) const
return &timer == m_system_timer.ptr(); return &timer == m_system_timer.ptr();
} }
void TimeManagement::set_epoch_time(time_t value) void TimeManagement::set_epoch_time(timespec ts)
{ {
timespec ticks = { 0, (long)ticks_this_second() * (long)1'000'000 };
timespec_sub(ts, ticks, ts);
InterruptDisabler disabler; InterruptDisabler disabler;
m_epoch_time = value; m_epoch_time = ts;
} }
time_t TimeManagement::epoch_time() const timespec TimeManagement::epoch_time() const
{ {
return m_epoch_time; timespec ts = m_epoch_time;
timespec ticks = { 0, (long)ticks_this_second() * (long)1'000'000 };
timespec_add(ts, ticks, ts);
return ts;
} }
void TimeManagement::initialize() void TimeManagement::initialize()
@ -94,14 +100,14 @@ TimeManagement::TimeManagement()
if (ACPI::is_enabled()) { if (ACPI::is_enabled()) {
if (!ACPI::Parser::the()->x86_specific_flags().cmos_rtc_not_present) { if (!ACPI::Parser::the()->x86_specific_flags().cmos_rtc_not_present) {
RTC::initialize(); RTC::initialize();
m_epoch_time += boot_time(); m_epoch_time.tv_sec += boot_time();
} else { } else {
klog() << "ACPI: RTC CMOS Not present"; klog() << "ACPI: RTC CMOS Not present";
} }
} else { } else {
// We just assume that we can access RTC CMOS, if ACPI isn't usable. // We just assume that we can access RTC CMOS, if ACPI isn't usable.
RTC::initialize(); RTC::initialize();
m_epoch_time += boot_time(); m_epoch_time.tv_sec += boot_time();
} }
if (probe_non_legacy_hardware_timers) { if (probe_non_legacy_hardware_timers) {
if (!probe_and_set_non_legacy_hardware_timers()) if (!probe_and_set_non_legacy_hardware_timers())
@ -116,8 +122,10 @@ TimeManagement::TimeManagement()
timeval TimeManagement::now_as_timeval() timeval TimeManagement::now_as_timeval()
{ {
auto* time_management = s_the.ptr(); timespec ts = s_the.ptr()->epoch_time();
return { time_management->epoch_time(), (suseconds_t)time_management->ticks_this_second() * (suseconds_t)1000 }; timeval tv;
timespec_to_timeval(ts, tv);
return tv;
} }
Vector<HardwareTimer*> TimeManagement::scan_and_initialize_periodic_timers() Vector<HardwareTimer*> TimeManagement::scan_and_initialize_periodic_timers()
@ -230,7 +238,7 @@ void TimeManagement::increment_time_since_boot(const RegisterState&)
if (++m_ticks_this_second >= m_time_keeper_timer->ticks_per_second()) { if (++m_ticks_this_second >= m_time_keeper_timer->ticks_per_second()) {
// FIXME: Synchronize with other clock somehow to prevent drifting apart. // FIXME: Synchronize with other clock somehow to prevent drifting apart.
++m_seconds_since_boot; ++m_seconds_since_boot;
++m_epoch_time; ++m_epoch_time.tv_sec;
m_ticks_this_second = 0; m_ticks_this_second = 0;
} }
} }

View file

@ -47,8 +47,8 @@ public:
static void initialize(); static void initialize();
static TimeManagement& the(); static TimeManagement& the();
time_t epoch_time() const; timespec epoch_time() const;
void set_epoch_time(time_t); void set_epoch_time(timespec);
time_t seconds_since_boot() const; time_t seconds_since_boot() const;
time_t ticks_per_second() const; time_t ticks_per_second() const;
time_t ticks_this_second() const; time_t ticks_this_second() const;
@ -72,7 +72,7 @@ private:
u32 m_ticks_this_second { 0 }; u32 m_ticks_this_second { 0 };
u32 m_seconds_since_boot { 0 }; u32 m_seconds_since_boot { 0 };
time_t m_epoch_time { 0 }; timespec m_epoch_time { 0, 0 };
RefPtr<HardwareTimer> m_system_timer; RefPtr<HardwareTimer> m_system_timer;
RefPtr<HardwareTimer> m_time_keeper_timer; RefPtr<HardwareTimer> m_time_keeper_timer;
}; };