From 465cb0413e231ae5ec6a8b5076266123c04732f8 Mon Sep 17 00:00:00 2001 From: psucien Date: Tue, 9 Jul 2024 12:12:15 +0200 Subject: [PATCH] kernel: equeue: minor refactoring --- src/common/debug.h | 2 + src/core/libraries/gnmdriver/gnmdriver.cpp | 29 ++++-- src/core/libraries/kernel/event_queue.cpp | 58 +++++++---- src/core/libraries/kernel/event_queue.h | 116 ++++++++++----------- src/core/libraries/kernel/event_queues.cpp | 54 ++++++---- src/core/libraries/kernel/event_queues.h | 1 + src/core/libraries/kernel/libkernel.cpp | 5 +- src/core/libraries/videoout/driver.cpp | 5 +- src/core/libraries/videoout/video_out.cpp | 14 ++- 9 files changed, 159 insertions(+), 125 deletions(-) diff --git a/src/common/debug.h b/src/common/debug.h index f9974228..50022a15 100644 --- a/src/common/debug.h +++ b/src/common/debug.h @@ -41,6 +41,8 @@ enum MarkersPallete : int { #define RENDERER_TRACE ZoneScopedC(RendererMarkerColor) #define HLE_TRACE ZoneScopedC(HleMarkerColor) +#define TRACE_HINT(str) ZoneText(str.c_str(), str.size()) + #define TRACE_WARN(msg) \ [](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg); #define TRACE_ERROR(msg) \ diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 653607af..dcf6d99e 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -26,6 +26,17 @@ using namespace AmdGpu; static std::unique_ptr liverpool; +enum GnmEventIdents : u64 { + Compute0RelMem = 0x00, + Compute1RelMem = 0x01, + Compute2RelMem = 0x02, + Compute3RelMem = 0x03, + Compute4RelMem = 0x04, + Compute5RelMem = 0x05, + Compute6RelMem = 0x06, + GfxEop = 0x40 +}; + enum ShaderStages : u32 { Cs, Ps, @@ -327,10 +338,6 @@ static inline u32* ClearContextState(u32* cmdbuf) { s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { LOG_TRACE(Lib_GnmDriver, "called"); - if (id != SceKernelEvent::Type::GfxEop) { - return ORBIS_OK; - } - ASSERT_MSG(id == SceKernelEvent::Type::GfxEop); if (!eq) { return ORBIS_KERNEL_ERROR_EBADF; @@ -338,20 +345,20 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { EqueueEvent kernel_event{}; kernel_event.event.ident = id; - kernel_event.event.filter = EVFILT_GRAPHICS_CORE; - kernel_event.event.flags = 1; + kernel_event.event.filter = SceKernelEvent::Filter::GraphicsCore; + kernel_event.event.flags = SceKernelEvent::Flags::Add; kernel_event.event.fflags = 0; kernel_event.event.data = id; kernel_event.event.udata = udata; - eq->addEvent(kernel_event); + eq->AddEvent(kernel_event); Platform::IrqC::Instance()->Register( Platform::InterruptId::GfxEop, [=](Platform::InterruptId irq) { ASSERT_MSG(irq == Platform::InterruptId::GfxEop, - "An unexpected IRQ occured"); // We need to conver IRQ# to event id and do + "An unexpected IRQ occured"); // We need to convert IRQ# to event id and do // proper filtering in trigger function - eq->triggerEvent(SceKernelEvent::Type::GfxEop, EVFILT_GRAPHICS_CORE, nullptr); + eq->TriggerEvent(GnmEventIdents::GfxEop, SceKernelEvent::Filter::GraphicsCore, nullptr); }, eq); return ORBIS_OK; @@ -455,13 +462,13 @@ int PS4_SYSV_ABI sceGnmDebugHardwareStatus() { s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) { LOG_TRACE(Lib_GnmDriver, "called"); - ASSERT_MSG(id == SceKernelEvent::Type::GfxEop); + ASSERT_MSG(id == GnmEventIdents::GfxEop); if (!eq) { return ORBIS_KERNEL_ERROR_EBADF; } - eq->removeEvent(id); + eq->RemoveEvent(id); Platform::IrqC::Instance()->Unregister(Platform::InterruptId::GfxEop, eq); return ORBIS_OK; diff --git a/src/core/libraries/kernel/event_queue.cpp b/src/core/libraries/kernel/event_queue.cpp index 6392d078..52c2c0da 100644 --- a/src/core/libraries/kernel/event_queue.cpp +++ b/src/core/libraries/kernel/event_queue.cpp @@ -8,32 +8,40 @@ namespace Libraries::Kernel { EqueueInternal::~EqueueInternal() = default; -int EqueueInternal::addEvent(const EqueueEvent& event) { +bool EqueueInternal::AddEvent(EqueueEvent& event) { std::scoped_lock lock{m_mutex}; - ASSERT(!event.isTriggered); + event.time_added = std::chrono::high_resolution_clock::now(); - // TODO check if event is already exists and return it. Currently we just add in m_events array - m_events.push_back(event); - return 0; + const auto& it = std::ranges::find(m_events, event); + if (it != m_events.cend()) { + *it = event; + } else { + m_events.emplace_back(event); + } + + return true; } -int EqueueInternal::removeEvent(u64 id) { +bool EqueueInternal::RemoveEvent(u64 id) { + bool has_found = false; std::scoped_lock lock{m_mutex}; - const auto& event_q = + const auto& it = std::ranges::find_if(m_events, [id](auto& ev) { return ev.event.ident == id; }); - ASSERT(event_q != m_events.cend()); - m_events.erase(event_q); - return 0; + if (it != m_events.cend()) { + m_events.erase(it); + has_found = true; + } + return has_found; } -int EqueueInternal::waitForEvents(SceKernelEvent* ev, int num, u32 micros) { +int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) { std::unique_lock lock{m_mutex}; int ret = 0; const auto predicate = [&] { - ret = getTriggeredEvents(ev, num); + ret = GetTriggeredEvents(ev, num); return ret > 0; }; @@ -45,28 +53,38 @@ int EqueueInternal::waitForEvents(SceKernelEvent* ev, int num, u32 micros) { return ret; } -bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) { +bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) { + bool has_found = false; { std::scoped_lock lock{m_mutex}; for (auto& event : m_events) { - if (event.event.ident == ident) { // event filter? - event.trigger(trigger_data); + ASSERT_MSG(event.event.filter == filter, + "Event to trigger doesn't match to queue events"); + if (event.event.ident == ident) { + event.Trigger(trigger_data); + has_found = true; } } } m_cond.notify_one(); - - return true; + return has_found; } -int EqueueInternal::getTriggeredEvents(SceKernelEvent* ev, int num) { +int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) { int ret = 0; for (auto& event : m_events) { - if (event.isTriggered) { + if (event.IsTriggered()) { + if (ev->flags & SceKernelEvent::Flags::Clear) { + event.Reset(); + } + ev[ret++] = event.event; - event.reset(); + + if (ret == num) { + break; + } } } diff --git a/src/core/libraries/kernel/event_queue.h b/src/core/libraries/kernel/event_queue.h index 8fc5f5d3..fa58512b 100644 --- a/src/core/libraries/kernel/event_queue.h +++ b/src/core/libraries/kernel/event_queue.h @@ -11,83 +11,76 @@ namespace Libraries::Kernel { -constexpr s16 EVFILT_READ = -1; -constexpr s16 EVFILT_WRITE = -2; -constexpr s16 EVFILT_AIO = -3; // attached to aio requests -constexpr s16 EVFILT_VNODE = -4; // attached to vnodes -constexpr s16 EVFILT_PROC = -5; // attached to struct proc -constexpr s16 EVFILT_SIGNAL = -6; // attached to struct proc -constexpr s16 EVFILT_TIMER = -7; // timers -constexpr s16 EVFILT_FS = -9; // filesystem events -constexpr s16 EVFILT_LIO = -10; // attached to lio requests -constexpr s16 EVFILT_USER = -11; // User events -constexpr s16 EVFILT_POLLING = -12; -constexpr s16 EVFILT_VIDEO_OUT = -13; -constexpr s16 EVFILT_GRAPHICS_CORE = -14; -constexpr s16 EVFILT_HRTIMER = -15; -constexpr s16 EVFILT_UVD_TRAP = -16; -constexpr s16 EVFILT_VCE_TRAP = -17; -constexpr s16 EVFILT_SDMA_TRAP = -18; -constexpr s16 EVFILT_REG_EV = -19; -constexpr s16 EVFILT_GPU_EXCEPTION = -20; -constexpr s16 EVFILT_GPU_SYSTEM_EXCEPTION = -21; -constexpr s16 EVFILT_GPU_DBGGC_EV = -22; -constexpr s16 EVFILT_SYSCOUNT = 22; - -constexpr u16 EV_ONESHOT = 0x10; // only report one occurrence -constexpr u16 EV_CLEAR = 0x20; // clear event state after reporting -constexpr u16 EV_RECEIPT = 0x40; // force EV_ERROR on success, data=0 -constexpr u16 EV_DISPATCH = 0x80; // disable event after reporting -constexpr u16 EV_SYSFLAGS = 0xF000; // reserved by system -constexpr u16 EV_FLAG1 = 0x2000; // filter-specific flag - class EqueueInternal; struct EqueueEvent; -using TriggerFunc = void (*)(EqueueEvent* event, void* trigger_data); -using ResetFunc = void (*)(EqueueEvent* event); -using DeleteFunc = void (*)(EqueueInternal* eq, EqueueEvent* event); - struct SceKernelEvent { - enum Type : u64 { - Compute0RelMem = 0x00, - Compute1RelMem = 0x01, - Compute2RelMem = 0x02, - Compute3RelMem = 0x03, - Compute4RelMem = 0x04, - Compute5RelMem = 0x05, - Compute6RelMem = 0x06, - GfxEop = 0x40 + enum Filter : s16 { + None = 0, + Read = -1, + Write = -2, + Aio = -3, + Vnode = -4, + Proc = -5, + Signal = -6, + Timer = -7, + Fs = -9, + Lio = -10, + User = -11, + Polling = -12, + VideoOut = -13, + GraphicsCore = -14, + HrTimer = -15, }; - u64 ident = 0; /* identifier for this event */ - s16 filter = 0; /* filter for event */ + enum Flags : u16 { + Add = 1u, + Delete = 2u, + Enable = 4u, + Disable = 8u, + OneShot = 0x10u, + Clear = 0x20u, + Receipt = 0x40u, + Dispatch = 0x80u, + Flag1 = 0x2000u, + System = 0xf000u, + }; + + u64 ident = 0; /* identifier for this event */ + Filter filter = Filter::None; /* filter for event */ u16 flags = 0; u32 fflags = 0; u64 data = 0; void* udata = nullptr; /* opaque user data identifier */ }; -struct Filter { - void* data = nullptr; -}; - struct EqueueEvent { - bool isTriggered = false; SceKernelEvent event; - Filter filter; + void* data = nullptr; + std::chrono::steady_clock::time_point time_added; - void reset() { - isTriggered = false; + void Reset() { + is_triggered = false; event.fflags = 0; event.data = 0; } - void trigger(void* data) { - isTriggered = true; + void Trigger(void* data) { + is_triggered = true; event.fflags++; event.data = reinterpret_cast(data); } + + bool IsTriggered() const { + return is_triggered; + } + + bool operator==(const EqueueEvent& ev) const { + return ev.event.ident == event.ident; + } + +private: + bool is_triggered = false; }; class EqueueInternal { @@ -97,11 +90,14 @@ public: void setName(const std::string& m_name) { this->m_name = m_name; } - int addEvent(const EqueueEvent& event); - int removeEvent(u64 id); - int waitForEvents(SceKernelEvent* ev, int num, u32 micros); - bool triggerEvent(u64 ident, s16 filter, void* trigger_data); - int getTriggeredEvents(SceKernelEvent* ev, int num); + const auto& GetName() const { + return m_name; + } + bool AddEvent(EqueueEvent& event); + bool RemoveEvent(u64 id); + int WaitForEvents(SceKernelEvent* ev, int num, u32 micros); + bool TriggerEvent(u64 ident, s16 filter, void* trigger_data); + int GetTriggeredEvents(SceKernelEvent* ev, int num); private: std::string m_name; diff --git a/src/core/libraries/kernel/event_queues.cpp b/src/core/libraries/kernel/event_queues.cpp index e2b151a8..1a262cf6 100644 --- a/src/core/libraries/kernel/event_queues.cpp +++ b/src/core/libraries/kernel/event_queues.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" +#include "common/debug.h" #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/kernel/event_queues.h" @@ -43,31 +44,33 @@ int PS4_SYSV_ABI sceKernelDeleteEqueue(SceKernelEqueue eq) { int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out, SceKernelUseconds* timo) { - LOG_INFO(Kernel_Event, "num = {}", num); + HLE_TRACE; + TRACE_HINT(eq->GetName()); + LOG_TRACE(Kernel_Event, "equeue = {} num = {}", eq->GetName(), num); if (eq == nullptr) { return ORBIS_KERNEL_ERROR_EBADF; } if (ev == nullptr) { - return SCE_KERNEL_ERROR_EFAULT; + return ORBIS_KERNEL_ERROR_EFAULT; } if (num < 1) { - return SCE_KERNEL_ERROR_EINVAL; + return ORBIS_KERNEL_ERROR_EINVAL; } if (timo == nullptr) { // wait until an event arrives without timing out - *out = eq->waitForEvents(ev, num, 0); + *out = eq->WaitForEvents(ev, num, 0); } if (timo != nullptr) { // Only events that have already arrived at the time of this function call can be received if (*timo == 0) { - *out = eq->getTriggeredEvents(ev, num); + *out = eq->GetTriggeredEvents(ev, num); } else { // Wait until an event arrives with timing out - *out = eq->waitForEvents(ev, num, *timo); + *out = eq->WaitForEvents(ev, num, *timo); } } @@ -83,16 +86,15 @@ int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) { return ORBIS_KERNEL_ERROR_EBADF; } - Kernel::EqueueEvent event{}; - event.isTriggered = false; + EqueueEvent event{}; event.event.ident = id; - event.event.filter = Kernel::EVFILT_USER; + event.event.filter = SceKernelEvent::Filter::User; event.event.udata = 0; - event.event.flags = 1; + event.event.flags = SceKernelEvent::Flags::Add; event.event.fflags = 0; event.event.data = 0; - return eq->addEvent(event); + return eq->AddEvent(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM; } int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) { @@ -100,33 +102,41 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) { return ORBIS_KERNEL_ERROR_EBADF; } - Kernel::EqueueEvent event{}; - event.isTriggered = false; + EqueueEvent event{}; event.event.ident = id; - event.event.filter = Kernel::EVFILT_USER; + event.event.filter = SceKernelEvent::Filter::User; event.event.udata = 0; - event.event.flags = 0x21; + event.event.flags = SceKernelEvent::Flags::Add | SceKernelEvent::Flags::Clear; event.event.fflags = 0; event.event.data = 0; - return eq->addEvent(event); + return eq->AddEvent(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM; } void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev) { - if (!ev) { - return nullptr; - } - + ASSERT(ev); return ev->udata; } int PS4_SYSV_ABI sceKernelTriggerUserEvent(SceKernelEqueue eq, int id, void* udata) { - eq->triggerEvent(id, Kernel::EVFILT_USER, udata); + if (eq == nullptr) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + if (!eq->TriggerEvent(id, SceKernelEvent::Filter::User, udata)) { + return ORBIS_KERNEL_ERROR_ENOENT; + } return ORBIS_OK; } int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id) { - eq->removeEvent(id); + if (eq == nullptr) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + if (!eq->RemoveEvent(id)) { + return ORBIS_KERNEL_ERROR_ENOENT; + } return ORBIS_OK; } 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 ce17a3f2..2a80422b 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -295,8 +295,8 @@ int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) { return 0; } -char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() { - char* path = "sys"; +const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() { + const char* path = "sys"; return path; } @@ -353,6 +353,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); diff --git a/src/core/libraries/videoout/driver.cpp b/src/core/libraries/videoout/driver.cpp index 7700a3a1..ece4ea01 100644 --- a/src/core/libraries/videoout/driver.cpp +++ b/src/core/libraries/videoout/driver.cpp @@ -196,7 +196,7 @@ void VideoOutDriver::Flip(std::chrono::microseconds timeout) { // Trigger flip events for the port. for (auto& event : req.port->flip_events) { if (event != nullptr) { - event->triggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, Kernel::EVFILT_VIDEO_OUT, + event->TriggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, Kernel::SceKernelEvent::Filter::VideoOut, reinterpret_cast(req.flip_arg)); } } @@ -252,7 +252,8 @@ void VideoOutDriver::Vblank() { // Trigger flip events for the port. for (auto& event : main_port.vblank_events) { if (event != nullptr) { - event->triggerEvent(SCE_VIDEO_OUT_EVENT_VBLANK, Kernel::EVFILT_VIDEO_OUT, nullptr); + event->TriggerEvent(SCE_VIDEO_OUT_EVENT_VBLANK, + Kernel::SceKernelEvent::Filter::VideoOut, nullptr); } } } diff --git a/src/core/libraries/videoout/video_out.cpp b/src/core/libraries/videoout/video_out.cpp index 7a0d237c..51cfcf4c 100644 --- a/src/core/libraries/videoout/video_out.cpp +++ b/src/core/libraries/videoout/video_out.cpp @@ -48,16 +48,15 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle, } Kernel::EqueueEvent event{}; - event.isTriggered = false; event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP; - event.event.filter = Kernel::EVFILT_VIDEO_OUT; + event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut; event.event.udata = udata; event.event.fflags = 0; event.event.data = 0; - event.filter.data = port; + event.data = port; port->flip_events.push_back(eq); - return eq->addEvent(event); + return eq->AddEvent(event); } s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata) { @@ -73,16 +72,15 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl } Kernel::EqueueEvent event{}; - event.isTriggered = false; event.event.ident = SCE_VIDEO_OUT_EVENT_VBLANK; - event.event.filter = Kernel::EVFILT_VIDEO_OUT; + event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut; event.event.udata = udata; event.event.fflags = 0; event.event.data = 0; - event.filter.data = port; + event.data = port; port->vblank_events.push_back(eq); - return eq->addEvent(event); + return eq->AddEvent(event); } s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,