#define pr_fmt(fmt) "clock: " fmt #include #include #include #include #include #include static struct clock* active_clock = nullptr; static uint64_t counter_base = 0; static struct spinlock lock = {}; static uint64_t clock_get_elapsed_ns_locked() { if (__unlikely(!active_clock)) return 0; return counter_base + active_clock->get_elapsed_ns(active_clock); } bool clock_available() { spin_lock(&lock); bool available = active_clock != nullptr; spin_unlock(&lock); return available; } uint64_t clock_get_elapsed_ns() { spin_lock(&lock); uint64_t elapsed = clock_get_elapsed_ns_locked(); spin_unlock(&lock); return elapsed; } bool clock_switch(struct clock* clock) { spin_lock(&lock); if (active_clock) { if (clock->priority <= active_clock->priority) { spin_unlock(&lock); return false; } } uint64_t elapsed = clock_get_elapsed_ns_locked(); clock->reset(clock); counter_base = elapsed; active_clock = clock; spin_unlock(&lock); log("Switching to clock source \"%s\"\n", clock->name); return true; } void clock_spin_ns(uint64_t ns) { if (!clock_available()) { log_err("Unable to sleep for %lu ns, no clock available!\n", ns); return; } uint64_t target = clock_get_elapsed_ns() + ns; while (clock_get_elapsed_ns() < target) { arch_cpu_pause(); } }