Forráskód Böngészése

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.
Nico Weber 4 éve
szülő
commit
e8131f503d

+ 2 - 3
Kernel/Syscalls/clock.cpp

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

+ 17 - 9
Kernel/Time/TimeManagement.cpp

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

+ 3 - 3
Kernel/Time/TimeManagement.h

@@ -47,8 +47,8 @@ public:
     static void initialize();
     static TimeManagement& the();
 
-    time_t epoch_time() const;
-    void set_epoch_time(time_t);
+    timespec epoch_time() const;
+    void set_epoch_time(timespec);
     time_t seconds_since_boot() const;
     time_t ticks_per_second() const;
     time_t ticks_this_second() const;
@@ -72,7 +72,7 @@ private:
 
     u32 m_ticks_this_second { 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_time_keeper_timer;
 };