From 53dd407ae357550407227dc3156da0d37840ff02 Mon Sep 17 00:00:00 2001 From: psucien Date: Tue, 18 Jun 2024 10:10:27 +0200 Subject: [PATCH] kernel: event_queue: initial `sceKernelAddHRTimerEvent` added --- src/core/libraries/kernel/event_queue.cpp | 14 +++++++++----- src/core/libraries/kernel/event_queue.h | 10 ++++++++++ src/core/libraries/kernel/event_queues.cpp | 22 ++++++++++++++++++++++ src/core/libraries/kernel/event_queues.h | 1 + src/core/libraries/kernel/libkernel.cpp | 1 + 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/core/libraries/kernel/event_queue.cpp b/src/core/libraries/kernel/event_queue.cpp index 81ccda8a..2a0cb3ef 100644 --- a/src/core/libraries/kernel/event_queue.cpp +++ b/src/core/libraries/kernel/event_queue.cpp @@ -8,15 +8,19 @@ namespace Libraries::Kernel { EqueueInternal::~EqueueInternal() = default; -int EqueueInternal::addEvent(const EqueueEvent& event) { +int EqueueInternal::addEvent(EqueueEvent& event) { std::scoped_lock lock{m_mutex}; - ASSERT(!event.IsTriggered()); + const auto start_clock = std::chrono::high_resolution_clock::now(); + event.filter.added_time_us = + std::chrono::time_point_cast(start_clock); const auto& it = std::ranges::find(m_events, event); - ASSERT(it == m_events.cend()); // TODO: update event if found - - m_events.push_back(event); + if (it != m_events.cend()) { + *it = event; + } else { + m_events.push_back(event); + } return 0; } diff --git a/src/core/libraries/kernel/event_queue.h b/src/core/libraries/kernel/event_queue.h index 6abcb33c..25f4c453 100644 --- a/src/core/libraries/kernel/event_queue.h +++ b/src/core/libraries/kernel/event_queue.h @@ -70,6 +70,7 @@ struct SceKernelEvent { struct Filter { void* data = nullptr; + std::chrono::time_point added_time_us; }; struct EqueueEvent { @@ -89,6 +90,15 @@ struct EqueueEvent { } bool IsTriggered() const { + if (event.filter == Kernel::EVFILT_HRTIMER) { + // For HR timers we don't want to waste time on spawning waiters. Instead, we will check + // for time out condition every time caller fetches the event status. + const auto now_clock = std::chrono::high_resolution_clock::now(); + const auto now_time_us = + std::chrono::time_point_cast(now_clock); + const auto delta = (now_time_us - filter.added_time_us).count(); + return (s64(event.data) - delta) <= 0; + } return is_triggered; } diff --git a/src/core/libraries/kernel/event_queues.cpp b/src/core/libraries/kernel/event_queues.cpp index 3b65af0d..e93c77fa 100644 --- a/src/core/libraries/kernel/event_queues.cpp +++ b/src/core/libraries/kernel/event_queues.cpp @@ -113,6 +113,28 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) { return eq->addEvent(event); } +s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) { + if (eq == nullptr) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + if (ts->tv_sec > 100 || ts->tv_nsec < 100'000) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + ASSERT(ts->tv_nsec > 1000); // assume 1us granularity + const auto total_us = ts->tv_sec * 1000'000 + ts->tv_nsec / 1000; + + Kernel::EqueueEvent event{}; + event.event.ident = id; + event.event.filter = Kernel::EVFILT_HRTIMER; + event.event.flags = 0x11; + event.event.fflags = 0; + event.event.data = total_us; + event.event.udata = udata; + + return eq->addEvent(event); +} + void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev) { if (!ev) { return nullptr; diff --git a/src/core/libraries/kernel/event_queues.h b/src/core/libraries/kernel/event_queues.h index 8c1521b7..2549203e 100644 --- a/src/core/libraries/kernel/event_queues.h +++ b/src/core/libraries/kernel/event_queues.h @@ -19,5 +19,6 @@ int PS4_SYSV_ABI sceKernelTriggerUserEvent(SceKernelEqueue eq, int id, void* uda int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id); int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id); int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id); +s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata); } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index a4ca5901..9bc54a1d 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -324,6 +324,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData); LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent); LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge); + LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent); LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent); LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);