diff options
| author | 2024-02-06 23:09:43 -0500 | |
|---|---|---|
| committer | 2024-02-07 12:14:46 -0500 | |
| commit | 9404633bfd1e4ea23ccf8ef526b2b4c564ba512d (patch) | |
| tree | fe37bb0acf2383ecc625f3c278000ba5869ccbaa /src/core/hle/service/os | |
| parent | Merge pull request #12883 from FernandoS27/memory_manager_mem (diff) | |
| download | yuzu-9404633bfd1e4ea23ccf8ef526b2b4c564ba512d.tar.gz yuzu-9404633bfd1e4ea23ccf8ef526b2b4c564ba512d.tar.xz yuzu-9404633bfd1e4ea23ccf8ef526b2b4c564ba512d.zip | |
service: add os types and multi wait API
Diffstat (limited to 'src/core/hle/service/os')
| -rw-r--r-- | src/core/hle/service/os/event.cpp | 31 | ||||
| -rw-r--r-- | src/core/hle/service/os/event.h | 31 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait.cpp | 59 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait.h | 36 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait_holder.cpp | 25 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait_holder.h | 44 | ||||
| -rw-r--r-- | src/core/hle/service/os/multi_wait_utils.h | 109 | ||||
| -rw-r--r-- | src/core/hle/service/os/mutex.cpp | 46 | ||||
| -rw-r--r-- | src/core/hle/service/os/mutex.h | 31 |
9 files changed, 412 insertions, 0 deletions
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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_event.h" | ||
| 5 | #include "core/hle/service/kernel_helpers.h" | ||
| 6 | #include "core/hle/service/os/event.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | |||
| 10 | Event::Event(KernelHelpers::ServiceContext& ctx) { | ||
| 11 | m_event = ctx.CreateEvent("Event"); | ||
| 12 | } | ||
| 13 | |||
| 14 | Event::~Event() { | ||
| 15 | m_event->GetReadableEvent().Close(); | ||
| 16 | m_event->Close(); | ||
| 17 | } | ||
| 18 | |||
| 19 | void Event::Signal() { | ||
| 20 | m_event->Signal(); | ||
| 21 | } | ||
| 22 | |||
| 23 | void Event::Clear() { | ||
| 24 | m_event->Clear(); | ||
| 25 | } | ||
| 26 | |||
| 27 | Kernel::KReadableEvent* Event::GetHandle() { | ||
| 28 | return &m_event->GetReadableEvent(); | ||
| 29 | } | ||
| 30 | |||
| 31 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | namespace Kernel { | ||
| 7 | class KEvent; | ||
| 8 | class KReadableEvent; | ||
| 9 | } // namespace Kernel | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | |||
| 13 | namespace KernelHelpers { | ||
| 14 | class ServiceContext; | ||
| 15 | } | ||
| 16 | |||
| 17 | class Event { | ||
| 18 | public: | ||
| 19 | explicit Event(KernelHelpers::ServiceContext& ctx); | ||
| 20 | ~Event(); | ||
| 21 | |||
| 22 | void Signal(); | ||
| 23 | void Clear(); | ||
| 24 | |||
| 25 | Kernel::KReadableEvent* GetHandle(); | ||
| 26 | |||
| 27 | private: | ||
| 28 | Kernel::KEvent* m_event; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 5 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 6 | #include "core/hle/kernel/kernel.h" | ||
| 7 | #include "core/hle/kernel/svc_common.h" | ||
| 8 | #include "core/hle/service/os/multi_wait.h" | ||
| 9 | |||
| 10 | namespace Service { | ||
| 11 | |||
| 12 | MultiWait::MultiWait() = default; | ||
| 13 | MultiWait::~MultiWait() = default; | ||
| 14 | |||
| 15 | MultiWaitHolder* MultiWait::WaitAny(Kernel::KernelCore& kernel) { | ||
| 16 | return this->TimedWaitImpl(kernel, -1); | ||
| 17 | } | ||
| 18 | |||
| 19 | MultiWaitHolder* MultiWait::TryWaitAny(Kernel::KernelCore& kernel) { | ||
| 20 | return this->TimedWaitImpl(kernel, 0); | ||
| 21 | } | ||
| 22 | |||
| 23 | MultiWaitHolder* MultiWait::TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns) { | ||
| 24 | return this->TimedWaitImpl(kernel, kernel.HardwareTimer().GetTick() + timeout_ns); | ||
| 25 | } | ||
| 26 | |||
| 27 | MultiWaitHolder* MultiWait::TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick) { | ||
| 28 | std::array<MultiWaitHolder*, Kernel::Svc::ArgumentHandleCountMax> holders{}; | ||
| 29 | std::array<Kernel::KSynchronizationObject*, Kernel::Svc::ArgumentHandleCountMax> objects{}; | ||
| 30 | |||
| 31 | s32 out_index = -1; | ||
| 32 | s32 num_objects = 0; | ||
| 33 | |||
| 34 | for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it++) { | ||
| 35 | ASSERT(num_objects < Kernel::Svc::ArgumentHandleCountMax); | ||
| 36 | holders[num_objects] = std::addressof(*it); | ||
| 37 | objects[num_objects] = it->GetNativeHandle(); | ||
| 38 | num_objects++; | ||
| 39 | } | ||
| 40 | |||
| 41 | Kernel::KSynchronizationObject::Wait(kernel, std::addressof(out_index), objects.data(), | ||
| 42 | num_objects, timeout_tick); | ||
| 43 | |||
| 44 | if (out_index == -1) { | ||
| 45 | return nullptr; | ||
| 46 | } else { | ||
| 47 | return holders[out_index]; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | void MultiWait::MoveAll(MultiWait* other) { | ||
| 52 | while (!other->m_wait_list.empty()) { | ||
| 53 | MultiWaitHolder& holder = other->m_wait_list.front(); | ||
| 54 | holder.UnlinkFromMultiWait(); | ||
| 55 | holder.LinkToMultiWait(this); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/os/multi_wait_holder.h" | ||
| 7 | |||
| 8 | namespace Kernel { | ||
| 9 | class KernelCore; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | |||
| 14 | class MultiWait final { | ||
| 15 | public: | ||
| 16 | explicit MultiWait(); | ||
| 17 | ~MultiWait(); | ||
| 18 | |||
| 19 | public: | ||
| 20 | MultiWaitHolder* WaitAny(Kernel::KernelCore& kernel); | ||
| 21 | MultiWaitHolder* TryWaitAny(Kernel::KernelCore& kernel); | ||
| 22 | MultiWaitHolder* TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns); | ||
| 23 | // TODO: SdkReplyAndReceive? | ||
| 24 | |||
| 25 | void MoveAll(MultiWait* other); | ||
| 26 | |||
| 27 | private: | ||
| 28 | MultiWaitHolder* TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick); | ||
| 29 | |||
| 30 | private: | ||
| 31 | friend class MultiWaitHolder; | ||
| 32 | using ListType = Common::IntrusiveListMemberTraits<&MultiWaitHolder::m_list_node>::ListType; | ||
| 33 | ListType m_wait_list{}; | ||
| 34 | }; | ||
| 35 | |||
| 36 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/os/multi_wait.h" | ||
| 5 | #include "core/hle/service/os/multi_wait_holder.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | |||
| 9 | void MultiWaitHolder::LinkToMultiWait(MultiWait* multi_wait) { | ||
| 10 | if (m_multi_wait != nullptr) { | ||
| 11 | UNREACHABLE(); | ||
| 12 | } | ||
| 13 | |||
| 14 | m_multi_wait = multi_wait; | ||
| 15 | m_multi_wait->m_wait_list.push_back(*this); | ||
| 16 | } | ||
| 17 | |||
| 18 | void MultiWaitHolder::UnlinkFromMultiWait() { | ||
| 19 | if (m_multi_wait) { | ||
| 20 | m_multi_wait->m_wait_list.erase(m_multi_wait->m_wait_list.iterator_to(*this)); | ||
| 21 | m_multi_wait = nullptr; | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/intrusive_list.h" | ||
| 7 | |||
| 8 | namespace Kernel { | ||
| 9 | class KSynchronizationObject; | ||
| 10 | } // namespace Kernel | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | |||
| 14 | class MultiWait; | ||
| 15 | |||
| 16 | class MultiWaitHolder { | ||
| 17 | public: | ||
| 18 | explicit MultiWaitHolder(Kernel::KSynchronizationObject* native_handle) | ||
| 19 | : m_native_handle(native_handle) {} | ||
| 20 | |||
| 21 | void LinkToMultiWait(MultiWait* multi_wait); | ||
| 22 | void UnlinkFromMultiWait(); | ||
| 23 | |||
| 24 | void SetUserData(uintptr_t user_data) { | ||
| 25 | m_user_data = user_data; | ||
| 26 | } | ||
| 27 | |||
| 28 | uintptr_t GetUserData() const { | ||
| 29 | return m_user_data; | ||
| 30 | } | ||
| 31 | |||
| 32 | Kernel::KSynchronizationObject* GetNativeHandle() const { | ||
| 33 | return m_native_handle; | ||
| 34 | } | ||
| 35 | |||
| 36 | private: | ||
| 37 | friend class MultiWait; | ||
| 38 | Common::IntrusiveListNode m_list_node{}; | ||
| 39 | MultiWait* m_multi_wait{}; | ||
| 40 | Kernel::KSynchronizationObject* m_native_handle{}; | ||
| 41 | uintptr_t m_user_data{}; | ||
| 42 | }; | ||
| 43 | |||
| 44 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/os/multi_wait.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | |||
| 10 | namespace impl { | ||
| 11 | |||
| 12 | class AutoMultiWaitHolder { | ||
| 13 | private: | ||
| 14 | MultiWaitHolder m_holder; | ||
| 15 | |||
| 16 | public: | ||
| 17 | template <typename T> | ||
| 18 | explicit AutoMultiWaitHolder(MultiWait* multi_wait, T&& arg) : m_holder(arg) { | ||
| 19 | m_holder.LinkToMultiWait(multi_wait); | ||
| 20 | } | ||
| 21 | |||
| 22 | ~AutoMultiWaitHolder() { | ||
| 23 | m_holder.UnlinkFromMultiWait(); | ||
| 24 | } | ||
| 25 | |||
| 26 | std::pair<MultiWaitHolder*, int> ConvertResult(const std::pair<MultiWaitHolder*, int> result, | ||
| 27 | int index) { | ||
| 28 | if (result.first == std::addressof(m_holder)) { | ||
| 29 | return std::make_pair(static_cast<MultiWaitHolder*>(nullptr), index); | ||
| 30 | } else { | ||
| 31 | return result; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | using WaitAnyFunction = decltype(&MultiWait::WaitAny); | ||
| 37 | |||
| 38 | inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel, | ||
| 39 | MultiWait* multi_wait, WaitAnyFunction func, | ||
| 40 | int) { | ||
| 41 | return std::pair<MultiWaitHolder*, int>((multi_wait->*func)(kernel), -1); | ||
| 42 | } | ||
| 43 | |||
| 44 | template <typename T, typename... Args> | ||
| 45 | inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel, | ||
| 46 | MultiWait* multi_wait, WaitAnyFunction func, | ||
| 47 | int index, T&& x, Args&&... args) { | ||
| 48 | AutoMultiWaitHolder holder(multi_wait, std::forward<T>(x)); | ||
| 49 | return holder.ConvertResult( | ||
| 50 | WaitAnyImpl(kernel, multi_wait, func, index + 1, std::forward<Args>(args)...), index); | ||
| 51 | } | ||
| 52 | |||
| 53 | template <typename... Args> | ||
| 54 | inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel, | ||
| 55 | MultiWait* multi_wait, WaitAnyFunction func, | ||
| 56 | Args&&... args) { | ||
| 57 | return WaitAnyImpl(kernel, multi_wait, func, 0, std::forward<Args>(args)...); | ||
| 58 | } | ||
| 59 | |||
| 60 | template <typename... Args> | ||
| 61 | inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel, | ||
| 62 | WaitAnyFunction func, Args&&... args) { | ||
| 63 | MultiWait temp_multi_wait; | ||
| 64 | return WaitAnyImpl(kernel, std::addressof(temp_multi_wait), func, 0, | ||
| 65 | std::forward<Args>(args)...); | ||
| 66 | } | ||
| 67 | |||
| 68 | class NotBoolButInt { | ||
| 69 | public: | ||
| 70 | constexpr NotBoolButInt(int v) : m_value(v) {} | ||
| 71 | constexpr operator int() const { | ||
| 72 | return m_value; | ||
| 73 | } | ||
| 74 | explicit operator bool() const = delete; | ||
| 75 | |||
| 76 | private: | ||
| 77 | int m_value; | ||
| 78 | }; | ||
| 79 | |||
| 80 | } // namespace impl | ||
| 81 | |||
| 82 | template <typename... Args> | ||
| 83 | requires(sizeof...(Args) > 0) | ||
| 84 | inline std::pair<MultiWaitHolder*, int> WaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait, | ||
| 85 | Args&&... args) { | ||
| 86 | return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, multi_wait, std::forward<Args>(args)...); | ||
| 87 | } | ||
| 88 | |||
| 89 | template <typename... Args> | ||
| 90 | requires(sizeof...(Args) > 0) | ||
| 91 | inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) { | ||
| 92 | return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward<Args>(args)...).second; | ||
| 93 | } | ||
| 94 | |||
| 95 | template <typename... Args> | ||
| 96 | requires(sizeof...(Args) > 0) | ||
| 97 | inline std::pair<MultiWaitHolder*, int> TryWaitAny(Kernel::KernelCore& kernel, | ||
| 98 | MultiWait* multi_wait, Args&&... args) { | ||
| 99 | return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, multi_wait, | ||
| 100 | std::forward<Args>(args)...); | ||
| 101 | } | ||
| 102 | |||
| 103 | template <typename... Args> | ||
| 104 | requires(sizeof...(Args) > 0) | ||
| 105 | inline impl::NotBoolButInt TryWaitAny(Kernel::KernelCore& kernel, Args&&... args) { | ||
| 106 | return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, std::forward<Args>(args)...).second; | ||
| 107 | } | ||
| 108 | |||
| 109 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/kernel/k_event.h" | ||
| 6 | #include "core/hle/kernel/k_synchronization_object.h" | ||
| 7 | #include "core/hle/service/os/mutex.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | |||
| 11 | Mutex::Mutex(Core::System& system) : m_system(system) { | ||
| 12 | m_event = Kernel::KEvent::Create(system.Kernel()); | ||
| 13 | m_event->Initialize(nullptr); | ||
| 14 | |||
| 15 | // Register the event. | ||
| 16 | Kernel::KEvent::Register(system.Kernel(), m_event); | ||
| 17 | |||
| 18 | ASSERT(R_SUCCEEDED(m_event->Signal())); | ||
| 19 | } | ||
| 20 | |||
| 21 | Mutex::~Mutex() { | ||
| 22 | m_event->GetReadableEvent().Close(); | ||
| 23 | m_event->Close(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void Mutex::lock() { | ||
| 27 | // Infinitely retry until we successfully clear the event. | ||
| 28 | while (R_FAILED(m_event->GetReadableEvent().Reset())) { | ||
| 29 | s32 index; | ||
| 30 | Kernel::KSynchronizationObject* obj = &m_event->GetReadableEvent(); | ||
| 31 | |||
| 32 | // The event was already cleared! | ||
| 33 | // Wait for it to become signaled again. | ||
| 34 | ASSERT(R_SUCCEEDED( | ||
| 35 | Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &index, &obj, 1, -1))); | ||
| 36 | } | ||
| 37 | |||
| 38 | // We successfully cleared the event, and now have exclusive ownership. | ||
| 39 | } | ||
| 40 | |||
| 41 | void Mutex::unlock() { | ||
| 42 | // Unlock. | ||
| 43 | ASSERT(R_SUCCEEDED(m_event->Signal())); | ||
| 44 | } | ||
| 45 | |||
| 46 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | |||
| 8 | namespace Core { | ||
| 9 | class System; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | class KEvent; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service { | ||
| 17 | |||
| 18 | class Mutex { | ||
| 19 | public: | ||
| 20 | explicit Mutex(Core::System& system); | ||
| 21 | ~Mutex(); | ||
| 22 | |||
| 23 | void lock(); | ||
| 24 | void unlock(); | ||
| 25 | |||
| 26 | private: | ||
| 27 | Core::System& m_system; | ||
| 28 | Kernel::KEvent* m_event{}; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace Service | ||