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/os/event.cpp similarity index 93% rename from src/core/hle/service/event.cpp rename to src/core/hle/service/os/event.cpp index 375660d72..ec52c17fd 100644 --- a/src/core/hle/service/event.cpp +++ b/src/core/hle/service/os/event.cpp @@ -2,8 +2,8 @@ // 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" +#include "core/hle/service/os/event.h" namespace Service { diff --git a/src/core/hle/service/event.h b/src/core/hle/service/os/event.h similarity index 100% rename from src/core/hle/service/event.h rename to src/core/hle/service/os/event.h 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/mutex.cpp b/src/core/hle/service/os/mutex.cpp similarity index 96% rename from src/core/hle/service/mutex.cpp rename to src/core/hle/service/os/mutex.cpp index b0ff71d1b..6009f4866 100644 --- a/src/core/hle/service/mutex.cpp +++ b/src/core/hle/service/os/mutex.cpp @@ -4,7 +4,7 @@ #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" +#include "core/hle/service/os/mutex.h" namespace Service { diff --git a/src/core/hle/service/mutex.h b/src/core/hle/service/os/mutex.h similarity index 100% rename from src/core/hle/service/mutex.h rename to src/core/hle/service/os/mutex.h 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;