/* * InputEvents.cpp * Shared input activity event source * Copyright (c) 2026 Daniel Hammer */ #include "InputEvents.hpp" #include #include #include namespace Drivers::InputEvents { static std::atomic g_serial{1}; static uint8_t g_waitObject; struct WaitContext { uint64_t observedSerial; }; static bool SerialStillObserved(void* rawContext) { auto* context = static_cast(rawContext); return context != nullptr && g_serial.load(std::memory_order_acquire) == context->observedSerial; } uint64_t GetSerial() { return g_serial.load(std::memory_order_acquire); } void NotifyActivity() { g_serial.fetch_add(1, std::memory_order_release); Sched::WakeObjectWaiters(&g_waitObject); } uint64_t WaitForChange(uint64_t observedSerial, uint64_t timeoutMs) { uint64_t current = GetSerial(); if (current != observedSerial || timeoutMs == 0) { return current; } WaitContext context{observedSerial}; uint64_t start = Timekeeping::GetMilliseconds(); for (;;) { current = GetSerial(); if (current != observedSerial) { return current; } uint64_t waitMs = 0; if (timeoutMs == UINT64_MAX) { waitMs = 0; } else { uint64_t elapsed = Timekeeping::GetMilliseconds() - start; if (elapsed >= timeoutMs) { return current; } waitMs = timeoutMs - elapsed; if (waitMs == 0) { waitMs = 1; } } Sched::BlockOnObjectIf(&g_waitObject, waitMs, SerialStillObserved, &context); } } }