diff --git a/src/core/libraries/kernel/event_flag/event_flag.cpp b/src/core/libraries/kernel/event_flag/event_flag.cpp index 01efad70..fffce0f7 100644 --- a/src/core/libraries/kernel/event_flag/event_flag.cpp +++ b/src/core/libraries/kernel/event_flag/event_flag.cpp @@ -72,13 +72,60 @@ int PS4_SYSV_ABI sceKernelCancelEventFlag(OrbisKernelEventFlag ef, u64 setPatter return ORBIS_OK; } int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) { - LOG_ERROR(Kernel_Event, "(STUBBED) called"); + LOG_TRACE(Kernel_Event, "called"); + if (ef == nullptr) { + return ORBIS_KERNEL_ERROR_ESRCH; + } + ef->Set(bitPattern); return ORBIS_OK; } int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode, u64* pResultPat) { - LOG_ERROR(Kernel_Event, "(STUBBED) called"); - return ORBIS_OK; + LOG_INFO(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode); + + if (ef == nullptr) { + return ORBIS_KERNEL_ERROR_ESRCH; + } + + if (bitPattern == 0) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + + EventFlagInternal::WaitMode wait = EventFlagInternal::WaitMode::And; + EventFlagInternal::ClearMode clear = EventFlagInternal::ClearMode::None; + + switch (waitMode & 0xf) { + case 0x01: + wait = EventFlagInternal::WaitMode::And; + break; + case 0x02: + wait = EventFlagInternal::WaitMode::Or; + break; + default: + UNREACHABLE(); + } + + switch (waitMode & 0xf0) { + case 0x00: + clear = EventFlagInternal::ClearMode::None; + break; + case 0x10: + clear = EventFlagInternal::ClearMode::All; + break; + case 0x20: + clear = EventFlagInternal::ClearMode::Bits; + break; + default: + UNREACHABLE(); + } + + auto result = ef->Poll(bitPattern, wait, clear, pResultPat); + + if (result != ORBIS_OK) { + LOG_ERROR(Kernel_Event, "returned {}", result); + } + + return result; } int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode, u64* pResultPat, OrbisKernelUseconds* pTimeout) { diff --git a/src/core/libraries/kernel/event_flag/event_flag_obj.cpp b/src/core/libraries/kernel/event_flag/event_flag_obj.cpp index 86250c35..069ae9dc 100644 --- a/src/core/libraries/kernel/event_flag/event_flag_obj.cpp +++ b/src/core/libraries/kernel/event_flag/event_flag_obj.cpp @@ -70,4 +70,24 @@ int EventFlagInternal::Wait(u64 bits, WaitMode wait_mode, ClearMode clear_mode, return ORBIS_OK; } + +int EventFlagInternal::Poll(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result) { + u32 micros = 0; + return Wait(bits, wait_mode, clear_mode, result, µs); +} + +void EventFlagInternal::Set(u64 bits) { + std::unique_lock lock{m_mutex}; + + while (m_status != Status::Set) { + m_mutex.unlock(); + std::this_thread::sleep_for(std::chrono::microseconds(10)); + m_mutex.lock(); + } + + m_bits |= bits; + + m_cond_var.notify_all(); +} + } // namespace Libraries::Kernel \ No newline at end of file diff --git a/src/core/libraries/kernel/event_flag/event_flag_obj.h b/src/core/libraries/kernel/event_flag/event_flag_obj.h index 9284ec56..a4a85a8e 100644 --- a/src/core/libraries/kernel/event_flag/event_flag_obj.h +++ b/src/core/libraries/kernel/event_flag/event_flag_obj.h @@ -18,6 +18,8 @@ public: : m_name(name), m_single_thread(single), m_fifo(fifo), m_bits(bits){}; int Wait(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result, u32* ptr_micros); + int Poll(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result); + void Set(u64 bits); private: enum class Status { Set, Canceled, Deleted };