diff --git a/kernel/src/Log.cpp b/kernel/src/Log.cpp index e8c876c7..5ea34f29 100644 --- a/kernel/src/Log.cpp +++ b/kernel/src/Log.cpp @@ -35,7 +35,9 @@ static void log_serial(LogLevel level, const char* format, va_list origin) "\x1b[0m ", ansi_color_codes_per_log_level[(int)level], log_level_letters[(int)level]); - Serial::printf("%4zu.%.3zu ", Timer::ticks(), Timer::ticks_ms() - (Timer::ticks() * 1000)); + auto* time = Timer::monotonic_clock(); + + Serial::printf("%4zu.%.3zu ", time->tv_sec, time->tv_nsec / 1'000'000); // NOTE: We do this manually because of a lack of vprintf() in both Serial and TextConsole. cstyle_format( diff --git a/kernel/src/arch/Timer.cpp b/kernel/src/arch/Timer.cpp index 3530095f..8220a3b8 100644 --- a/kernel/src/arch/Timer.cpp +++ b/kernel/src/arch/Timer.cpp @@ -4,10 +4,8 @@ #include "boot/bootboot.h" #include -// NOTE: Storing these values as unsigned integers doesn't allow for pre-epoch times. -// We are in 2023 anyway, not sure why anybody would want to set their computer's time to 1945. -static u64 timer_ticks = 0; -static u64 boot_timestamp; +static struct timespec s_monotonic_clock = { 0, 0 }; +static struct timespec s_realtime_clock; static inline constexpr bool isleap(u32 year) { @@ -56,84 +54,33 @@ extern const BOOTBOOT bootboot; namespace Timer { + static struct timespec s_interval = { .tv_sec = 0, .tv_nsec = ARCH_TIMER_RESOLUTION * 1000 }; + void tick() { - timer_ticks += ARCH_TIMER_RESOLUTION; + timespecadd(&s_monotonic_clock, &s_interval, &s_monotonic_clock); + timespecadd(&s_realtime_clock, &s_interval, &s_realtime_clock); } - usize raw_ticks() + struct timespec* monotonic_clock() { - return timer_ticks; + return &s_monotonic_clock; } - usize ticks() + struct timespec* realtime_clock() { - return ticks_us() / US_PER_SECOND; - } - - usize ticks_ms() - { - return timer_ticks / 1000; - } - - usize ticks_us() - { - return timer_ticks; - } - - usize ticks_ns() - { - return ticks_us() * 1000; - } - - usize boot() - { - return boot_timestamp / US_PER_SECOND; - } - - usize boot_ms() - { - return boot_timestamp / 1000; - } - - usize boot_us() - { - return boot_timestamp; - } - - usize boot_ns() - { - return boot_timestamp * 1000; - } - - usize clock() - { - return boot() + ticks(); - } - - usize clock_ms() - { - return boot_ms() + ticks_ms(); - } - - usize clock_us() - { - return boot_us() + ticks_us(); - } - - usize clock_ns() - { - return boot_ns() + ticks_ns(); + return &s_realtime_clock; } void init() { - boot_timestamp = bootloader_time_to_unix(bootboot.datetime) * US_PER_SECOND; + s_realtime_clock.tv_sec = bootloader_time_to_unix(bootboot.datetime); + s_realtime_clock.tv_nsec = 0; arch_init(); } } bool should_invoke_scheduler() { - return (timer_ticks % 1000) == 0; + return (s_realtime_clock.tv_nsec % 1'000'000) == 0; } diff --git a/kernel/src/arch/Timer.h b/kernel/src/arch/Timer.h index bcceb762..49c039fd 100644 --- a/kernel/src/arch/Timer.h +++ b/kernel/src/arch/Timer.h @@ -1,4 +1,5 @@ #pragma once +#include #include #ifdef ARCH_X86_64 @@ -15,22 +16,9 @@ namespace Timer { void tick(); - usize raw_ticks(); + struct timespec* monotonic_clock(); - usize ticks(); - usize ticks_ms(); - usize ticks_us(); - usize ticks_ns(); - - usize boot(); - usize boot_ms(); - usize boot_us(); - usize boot_ns(); - - usize clock(); - usize clock_ms(); - usize clock_us(); - usize clock_ns(); + struct timespec* realtime_clock(); void arch_init(); void init(); diff --git a/kernel/src/arch/x86_64/Timer.h b/kernel/src/arch/x86_64/Timer.h index 5619121e..52774e88 100644 --- a/kernel/src/arch/x86_64/Timer.h +++ b/kernel/src/arch/x86_64/Timer.h @@ -2,4 +2,5 @@ #include // Every timer tick is equivalent to 250 microseconds. +// FIXME: Change ARCH_TIMER_RESOLUTION to use nanoseconds. const usize ARCH_TIMER_RESOLUTION = 250; diff --git a/kernel/src/sys/clock_gettime.cpp b/kernel/src/sys/clock_gettime.cpp index d46a388d..d8083a5c 100644 --- a/kernel/src/sys/clock_gettime.cpp +++ b/kernel/src/sys/clock_gettime.cpp @@ -12,19 +12,11 @@ Result sys_clock_gettime(Registers*, SyscallArgs args) switch (id) { case CLOCK_MONOTONIC: { - usize ticks = Timer::ticks_ns(); - struct timespec kernel_ts; - kernel_ts.tv_sec = (time_t)(ticks / NS_PER_SECOND); - kernel_ts.tv_nsec = (long)(ticks % NS_PER_SECOND); - if (!MemoryManager::copy_to_user_typed(ts, &kernel_ts)) return err(EFAULT); + if (!MemoryManager::copy_to_user_typed(ts, Timer::monotonic_clock())) return err(EFAULT); break; } case CLOCK_REALTIME: { - usize clock = Timer::clock_ns(); - struct timespec kernel_ts; - kernel_ts.tv_sec = (time_t)(clock / NS_PER_SECOND); - kernel_ts.tv_nsec = (long)(clock % NS_PER_SECOND); - if (!MemoryManager::copy_to_user_typed(ts, &kernel_ts)) return err(EFAULT); + if (!MemoryManager::copy_to_user_typed(ts, Timer::realtime_clock())) return err(EFAULT); break; } default: return err(EINVAL); diff --git a/libc/include/bits/timespec.h b/libc/include/bits/timespec.h index 2cdfcdc3..66ec4dfa 100644 --- a/libc/include/bits/timespec.h +++ b/libc/include/bits/timespec.h @@ -18,3 +18,19 @@ struct timeval }; #endif + +#if defined(IN_MOON) || defined(_INCLUDE_TIMESPEC_MACROS) +#ifndef _TIMESPEC_MACROS_INCLUDED +#define _TIMESPEC_MACROS_INCLUDED +#define timespecadd(a, b, res) \ + do { \ + (res)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (res)->tv_nsec = (a)->tv_nsec + (b)->tv_nsec; \ + while ((res)->tv_nsec >= 1'000'000'000) \ + { \ + (res)->tv_sec++; \ + (res)->tv_nsec -= 1'000'000'000; \ + } \ + } while (0); +#endif +#endif diff --git a/libc/include/sys/time.h b/libc/include/sys/time.h index 761b2208..4b9b9c47 100644 --- a/libc/include/sys/time.h +++ b/libc/include/sys/time.h @@ -3,6 +3,8 @@ #ifndef _SYS_TIME_H #define _SYS_TIME_H +#define _INCLUDE_TIMESPEC_MACROS + #include #include