From 9404633bfd1e4ea23ccf8ef526b2b4c564ba512d Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 6 Feb 2024 23:09:43 -0500 Subject: service: add os types and multi wait API --- src/core/CMakeLists.txt | 13 ++- src/core/hle/service/am/applet.h | 2 +- src/core/hle/service/am/applet_data_broker.h | 2 +- src/core/hle/service/event.cpp | 31 -------- src/core/hle/service/event.h | 31 -------- src/core/hle/service/mutex.cpp | 46 ----------- src/core/hle/service/mutex.h | 31 -------- src/core/hle/service/os/event.cpp | 31 ++++++++ src/core/hle/service/os/event.h | 31 ++++++++ src/core/hle/service/os/multi_wait.cpp | 59 ++++++++++++++ src/core/hle/service/os/multi_wait.h | 36 +++++++++ src/core/hle/service/os/multi_wait_holder.cpp | 25 ++++++ src/core/hle/service/os/multi_wait_holder.h | 44 +++++++++++ src/core/hle/service/os/multi_wait_utils.h | 109 ++++++++++++++++++++++++++ src/core/hle/service/os/mutex.cpp | 46 +++++++++++ src/core/hle/service/os/mutex.h | 31 ++++++++ src/core/hle/service/server_manager.h | 2 +- 17 files changed, 424 insertions(+), 146 deletions(-) delete mode 100644 src/core/hle/service/event.cpp delete mode 100644 src/core/hle/service/event.h delete mode 100644 src/core/hle/service/mutex.cpp delete mode 100644 src/core/hle/service/mutex.h create mode 100644 src/core/hle/service/os/event.cpp create mode 100644 src/core/hle/service/os/event.h create mode 100644 src/core/hle/service/os/multi_wait.cpp create mode 100644 src/core/hle/service/os/multi_wait.h create mode 100644 src/core/hle/service/os/multi_wait_holder.cpp create mode 100644 src/core/hle/service/os/multi_wait_holder.h create mode 100644 src/core/hle/service/os/multi_wait_utils.h create mode 100644 src/core/hle/service/os/mutex.cpp create mode 100644 src/core/hle/service/os/mutex.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index eb8f643a2..1b44148f4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -548,8 +548,6 @@ add_library(core STATIC hle/service/es/es.h hle/service/eupld/eupld.cpp hle/service/eupld/eupld.h - hle/service/event.cpp - hle/service/event.h hle/service/fatal/fatal.cpp hle/service/fatal/fatal.h hle/service/fatal/fatal_p.cpp @@ -676,8 +674,6 @@ add_library(core STATIC hle/service/mm/mm_u.h hle/service/mnpp/mnpp_app.cpp hle/service/mnpp/mnpp_app.h - hle/service/mutex.cpp - hle/service/mutex.h hle/service/ncm/ncm.cpp hle/service/ncm/ncm.h hle/service/nfc/common/amiibo_crypto.cpp @@ -790,6 +786,15 @@ add_library(core STATIC hle/service/nvnflinger/window.h hle/service/olsc/olsc.cpp hle/service/olsc/olsc.h + hle/service/os/event.cpp + hle/service/os/event.h + hle/service/os/multi_wait_holder.cpp + hle/service/os/multi_wait_holder.h + hle/service/os/multi_wait_utils.h + hle/service/os/multi_wait.cpp + hle/service/os/multi_wait.h + hle/service/os/mutex.cpp + hle/service/os/mutex.h hle/service/pcie/pcie.cpp hle/service/pcie/pcie.h hle/service/pctl/pctl.cpp diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h index bce6f9050..b29ecdfed 100644 --- a/src/core/hle/service/am/applet.h +++ b/src/core/hle/service/am/applet.h @@ -9,8 +9,8 @@ #include "common/math_util.h" #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/caps/caps_types.h" -#include "core/hle/service/event.h" #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" #include "core/hle/service/service.h" #include "core/hle/service/am/am_types.h" diff --git a/src/core/hle/service/am/applet_data_broker.h b/src/core/hle/service/am/applet_data_broker.h index 12326fd04..5a1d43c11 100644 --- a/src/core/hle/service/am/applet_data_broker.h +++ b/src/core/hle/service/am/applet_data_broker.h @@ -7,8 +7,8 @@ #include #include -#include "core/hle/service/event.h" #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" union Result; diff --git a/src/core/hle/service/event.cpp b/src/core/hle/service/event.cpp deleted file mode 100644 index 375660d72..000000000 --- a/src/core/hle/service/event.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/kernel/k_event.h" -#include "core/hle/service/event.h" -#include "core/hle/service/kernel_helpers.h" - -namespace Service { - -Event::Event(KernelHelpers::ServiceContext& ctx) { - m_event = ctx.CreateEvent("Event"); -} - -Event::~Event() { - m_event->GetReadableEvent().Close(); - m_event->Close(); -} - -void Event::Signal() { - m_event->Signal(); -} - -void Event::Clear() { - m_event->Clear(); -} - -Kernel::KReadableEvent* Event::GetHandle() { - return &m_event->GetReadableEvent(); -} - -} // namespace Service diff --git a/src/core/hle/service/event.h b/src/core/hle/service/event.h deleted file mode 100644 index cdbc4635a..000000000 --- a/src/core/hle/service/event.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -namespace Kernel { -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Service { - -namespace KernelHelpers { -class ServiceContext; -} - -class Event { -public: - explicit Event(KernelHelpers::ServiceContext& ctx); - ~Event(); - - void Signal(); - void Clear(); - - Kernel::KReadableEvent* GetHandle(); - -private: - Kernel::KEvent* m_event; -}; - -} // namespace Service diff --git a/src/core/hle/service/mutex.cpp b/src/core/hle/service/mutex.cpp deleted file mode 100644 index b0ff71d1b..000000000 --- a/src/core/hle/service/mutex.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/service/mutex.h" - -namespace Service { - -Mutex::Mutex(Core::System& system) : m_system(system) { - m_event = Kernel::KEvent::Create(system.Kernel()); - m_event->Initialize(nullptr); - - // Register the event. - Kernel::KEvent::Register(system.Kernel(), m_event); - - ASSERT(R_SUCCEEDED(m_event->Signal())); -} - -Mutex::~Mutex() { - m_event->GetReadableEvent().Close(); - m_event->Close(); -} - -void Mutex::lock() { - // Infinitely retry until we successfully clear the event. - while (R_FAILED(m_event->GetReadableEvent().Reset())) { - s32 index; - Kernel::KSynchronizationObject* obj = &m_event->GetReadableEvent(); - - // The event was already cleared! - // Wait for it to become signaled again. - ASSERT(R_SUCCEEDED( - Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &index, &obj, 1, -1))); - } - - // We successfully cleared the event, and now have exclusive ownership. -} - -void Mutex::unlock() { - // Unlock. - ASSERT(R_SUCCEEDED(m_event->Signal())); -} - -} // namespace Service diff --git a/src/core/hle/service/mutex.h b/src/core/hle/service/mutex.h deleted file mode 100644 index 95ac9b117..000000000 --- a/src/core/hle/service/mutex.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_types.h" - -namespace Core { -class System; -} - -namespace Kernel { -class KEvent; -} - -namespace Service { - -class Mutex { -public: - explicit Mutex(Core::System& system); - ~Mutex(); - - void lock(); - void unlock(); - -private: - Core::System& m_system; - Kernel::KEvent* m_event{}; -}; - -} // namespace Service diff --git a/src/core/hle/service/os/event.cpp b/src/core/hle/service/os/event.cpp new file mode 100644 index 000000000..ec52c17fd --- /dev/null +++ b/src/core/hle/service/os/event.cpp @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/os/event.h" + +namespace Service { + +Event::Event(KernelHelpers::ServiceContext& ctx) { + m_event = ctx.CreateEvent("Event"); +} + +Event::~Event() { + m_event->GetReadableEvent().Close(); + m_event->Close(); +} + +void Event::Signal() { + m_event->Signal(); +} + +void Event::Clear() { + m_event->Clear(); +} + +Kernel::KReadableEvent* Event::GetHandle() { + return &m_event->GetReadableEvent(); +} + +} // namespace Service diff --git a/src/core/hle/service/os/event.h b/src/core/hle/service/os/event.h new file mode 100644 index 000000000..cdbc4635a --- /dev/null +++ b/src/core/hle/service/os/event.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Service { + +namespace KernelHelpers { +class ServiceContext; +} + +class Event { +public: + explicit Event(KernelHelpers::ServiceContext& ctx); + ~Event(); + + void Signal(); + void Clear(); + + Kernel::KReadableEvent* GetHandle(); + +private: + Kernel::KEvent* m_event; +}; + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait.cpp b/src/core/hle/service/os/multi_wait.cpp new file mode 100644 index 000000000..7b80d28be --- /dev/null +++ b/src/core/hle/service/os/multi_wait.cpp @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_hardware_timer.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_common.h" +#include "core/hle/service/os/multi_wait.h" + +namespace Service { + +MultiWait::MultiWait() = default; +MultiWait::~MultiWait() = default; + +MultiWaitHolder* MultiWait::WaitAny(Kernel::KernelCore& kernel) { + return this->TimedWaitImpl(kernel, -1); +} + +MultiWaitHolder* MultiWait::TryWaitAny(Kernel::KernelCore& kernel) { + return this->TimedWaitImpl(kernel, 0); +} + +MultiWaitHolder* MultiWait::TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns) { + return this->TimedWaitImpl(kernel, kernel.HardwareTimer().GetTick() + timeout_ns); +} + +MultiWaitHolder* MultiWait::TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick) { + std::array holders{}; + std::array objects{}; + + s32 out_index = -1; + s32 num_objects = 0; + + for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it++) { + ASSERT(num_objects < Kernel::Svc::ArgumentHandleCountMax); + holders[num_objects] = std::addressof(*it); + objects[num_objects] = it->GetNativeHandle(); + num_objects++; + } + + Kernel::KSynchronizationObject::Wait(kernel, std::addressof(out_index), objects.data(), + num_objects, timeout_tick); + + if (out_index == -1) { + return nullptr; + } else { + return holders[out_index]; + } +} + +void MultiWait::MoveAll(MultiWait* other) { + while (!other->m_wait_list.empty()) { + MultiWaitHolder& holder = other->m_wait_list.front(); + holder.UnlinkFromMultiWait(); + holder.LinkToMultiWait(this); + } +} + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait.h b/src/core/hle/service/os/multi_wait.h new file mode 100644 index 000000000..340c611b5 --- /dev/null +++ b/src/core/hle/service/os/multi_wait.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/os/multi_wait_holder.h" + +namespace Kernel { +class KernelCore; +} + +namespace Service { + +class MultiWait final { +public: + explicit MultiWait(); + ~MultiWait(); + +public: + MultiWaitHolder* WaitAny(Kernel::KernelCore& kernel); + MultiWaitHolder* TryWaitAny(Kernel::KernelCore& kernel); + MultiWaitHolder* TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns); + // TODO: SdkReplyAndReceive? + + void MoveAll(MultiWait* other); + +private: + MultiWaitHolder* TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick); + +private: + friend class MultiWaitHolder; + using ListType = Common::IntrusiveListMemberTraits<&MultiWaitHolder::m_list_node>::ListType; + ListType m_wait_list{}; +}; + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait_holder.cpp b/src/core/hle/service/os/multi_wait_holder.cpp new file mode 100644 index 000000000..01efa045b --- /dev/null +++ b/src/core/hle/service/os/multi_wait_holder.cpp @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/os/multi_wait.h" +#include "core/hle/service/os/multi_wait_holder.h" + +namespace Service { + +void MultiWaitHolder::LinkToMultiWait(MultiWait* multi_wait) { + if (m_multi_wait != nullptr) { + UNREACHABLE(); + } + + m_multi_wait = multi_wait; + m_multi_wait->m_wait_list.push_back(*this); +} + +void MultiWaitHolder::UnlinkFromMultiWait() { + if (m_multi_wait) { + m_multi_wait->m_wait_list.erase(m_multi_wait->m_wait_list.iterator_to(*this)); + m_multi_wait = nullptr; + } +} + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait_holder.h b/src/core/hle/service/os/multi_wait_holder.h new file mode 100644 index 000000000..646395a3f --- /dev/null +++ b/src/core/hle/service/os/multi_wait_holder.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/intrusive_list.h" + +namespace Kernel { +class KSynchronizationObject; +} // namespace Kernel + +namespace Service { + +class MultiWait; + +class MultiWaitHolder { +public: + explicit MultiWaitHolder(Kernel::KSynchronizationObject* native_handle) + : m_native_handle(native_handle) {} + + void LinkToMultiWait(MultiWait* multi_wait); + void UnlinkFromMultiWait(); + + void SetUserData(uintptr_t user_data) { + m_user_data = user_data; + } + + uintptr_t GetUserData() const { + return m_user_data; + } + + Kernel::KSynchronizationObject* GetNativeHandle() const { + return m_native_handle; + } + +private: + friend class MultiWait; + Common::IntrusiveListNode m_list_node{}; + MultiWait* m_multi_wait{}; + Kernel::KSynchronizationObject* m_native_handle{}; + uintptr_t m_user_data{}; +}; + +} // namespace Service diff --git a/src/core/hle/service/os/multi_wait_utils.h b/src/core/hle/service/os/multi_wait_utils.h new file mode 100644 index 000000000..96d3a10f3 --- /dev/null +++ b/src/core/hle/service/os/multi_wait_utils.h @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/os/multi_wait.h" + +namespace Service { + +namespace impl { + +class AutoMultiWaitHolder { +private: + MultiWaitHolder m_holder; + +public: + template + explicit AutoMultiWaitHolder(MultiWait* multi_wait, T&& arg) : m_holder(arg) { + m_holder.LinkToMultiWait(multi_wait); + } + + ~AutoMultiWaitHolder() { + m_holder.UnlinkFromMultiWait(); + } + + std::pair ConvertResult(const std::pair result, + int index) { + if (result.first == std::addressof(m_holder)) { + return std::make_pair(static_cast(nullptr), index); + } else { + return result; + } + } +}; + +using WaitAnyFunction = decltype(&MultiWait::WaitAny); + +inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, + MultiWait* multi_wait, WaitAnyFunction func, + int) { + return std::pair((multi_wait->*func)(kernel), -1); +} + +template +inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, + MultiWait* multi_wait, WaitAnyFunction func, + int index, T&& x, Args&&... args) { + AutoMultiWaitHolder holder(multi_wait, std::forward(x)); + return holder.ConvertResult( + WaitAnyImpl(kernel, multi_wait, func, index + 1, std::forward(args)...), index); +} + +template +inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, + MultiWait* multi_wait, WaitAnyFunction func, + Args&&... args) { + return WaitAnyImpl(kernel, multi_wait, func, 0, std::forward(args)...); +} + +template +inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, + WaitAnyFunction func, Args&&... args) { + MultiWait temp_multi_wait; + return WaitAnyImpl(kernel, std::addressof(temp_multi_wait), func, 0, + std::forward(args)...); +} + +class NotBoolButInt { +public: + constexpr NotBoolButInt(int v) : m_value(v) {} + constexpr operator int() const { + return m_value; + } + explicit operator bool() const = delete; + +private: + int m_value; +}; + +} // namespace impl + +template + requires(sizeof...(Args) > 0) +inline std::pair WaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait, + Args&&... args) { + return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, multi_wait, std::forward(args)...); +} + +template + requires(sizeof...(Args) > 0) +inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) { + return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward(args)...).second; +} + +template + requires(sizeof...(Args) > 0) +inline std::pair TryWaitAny(Kernel::KernelCore& kernel, + MultiWait* multi_wait, Args&&... args) { + return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, multi_wait, + std::forward(args)...); +} + +template + requires(sizeof...(Args) > 0) +inline impl::NotBoolButInt TryWaitAny(Kernel::KernelCore& kernel, Args&&... args) { + return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, std::forward(args)...).second; +} + +} // namespace Service diff --git a/src/core/hle/service/os/mutex.cpp b/src/core/hle/service/os/mutex.cpp new file mode 100644 index 000000000..6009f4866 --- /dev/null +++ b/src/core/hle/service/os/mutex.cpp @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/service/os/mutex.h" + +namespace Service { + +Mutex::Mutex(Core::System& system) : m_system(system) { + m_event = Kernel::KEvent::Create(system.Kernel()); + m_event->Initialize(nullptr); + + // Register the event. + Kernel::KEvent::Register(system.Kernel(), m_event); + + ASSERT(R_SUCCEEDED(m_event->Signal())); +} + +Mutex::~Mutex() { + m_event->GetReadableEvent().Close(); + m_event->Close(); +} + +void Mutex::lock() { + // Infinitely retry until we successfully clear the event. + while (R_FAILED(m_event->GetReadableEvent().Reset())) { + s32 index; + Kernel::KSynchronizationObject* obj = &m_event->GetReadableEvent(); + + // The event was already cleared! + // Wait for it to become signaled again. + ASSERT(R_SUCCEEDED( + Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &index, &obj, 1, -1))); + } + + // We successfully cleared the event, and now have exclusive ownership. +} + +void Mutex::unlock() { + // Unlock. + ASSERT(R_SUCCEEDED(m_event->Signal())); +} + +} // namespace Service diff --git a/src/core/hle/service/os/mutex.h b/src/core/hle/service/os/mutex.h new file mode 100644 index 000000000..95ac9b117 --- /dev/null +++ b/src/core/hle/service/os/mutex.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" + +namespace Core { +class System; +} + +namespace Kernel { +class KEvent; +} + +namespace Service { + +class Mutex { +public: + explicit Mutex(Core::System& system); + ~Mutex(); + + void lock(); + void unlock(); + +private: + Core::System& m_system; + Kernel::KEvent* m_event{}; +}; + +} // namespace Service diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h index c4bc07262..7481c8521 100644 --- a/src/core/hle/service/server_manager.h +++ b/src/core/hle/service/server_manager.h @@ -14,7 +14,7 @@ #include "common/thread.h" #include "core/hle/result.h" #include "core/hle/service/hle_ipc.h" -#include "core/hle/service/mutex.h" +#include "core/hle/service/os/mutex.h" namespace Core { class System; -- cgit v1.2.3