Files
MontaukOS/kernel/src/Drivers/Input/InputEvents.cpp
T

70 lines
1.9 KiB
C++

/*
* InputEvents.cpp
* Shared input activity event source
* Copyright (c) 2026 Daniel Hammer
*/
#include "InputEvents.hpp"
#include <atomic>
#include <Sched/Scheduler.hpp>
#include <Timekeeping/ApicTimer.hpp>
namespace Drivers::InputEvents {
static std::atomic<uint64_t> g_serial{1};
static uint8_t g_waitObject;
struct WaitContext {
uint64_t observedSerial;
};
static bool SerialStillObserved(void* rawContext) {
auto* context = static_cast<WaitContext*>(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);
}
}
}