From c5aefe42aaec7afa29d317709cacc8524f7add20 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 11 Feb 2020 10:46:25 -0400 Subject: Kernel: Change WaitObject to Synchronization object. In order to better reflect RE. --- src/core/CMakeLists.txt | 4 +- src/core/hle/kernel/client_session.cpp | 2 +- src/core/hle/kernel/client_session.h | 4 +- src/core/hle/kernel/hle_ipc.cpp | 20 ++--- src/core/hle/kernel/kernel.cpp | 4 +- src/core/hle/kernel/process.cpp | 2 +- src/core/hle/kernel/process.h | 4 +- src/core/hle/kernel/readable_event.cpp | 2 +- src/core/hle/kernel/readable_event.h | 4 +- src/core/hle/kernel/server_port.cpp | 2 +- src/core/hle/kernel/server_port.h | 4 +- src/core/hle/kernel/server_session.cpp | 2 +- src/core/hle/kernel/server_session.h | 4 +- src/core/hle/kernel/session.cpp | 2 +- src/core/hle/kernel/session.h | 4 +- src/core/hle/kernel/svc.cpp | 13 ++-- src/core/hle/kernel/synchronization_object.cpp | 104 +++++++++++++++++++++++++ src/core/hle/kernel/synchronization_object.h | 78 +++++++++++++++++++ src/core/hle/kernel/thread.cpp | 16 ++-- src/core/hle/kernel/thread.h | 22 +++--- src/core/hle/kernel/wait_object.cpp | 103 ------------------------ src/core/hle/kernel/wait_object.h | 77 ------------------ src/yuzu/debugger/wait_tree.cpp | 35 +++++---- src/yuzu/debugger/wait_tree.h | 22 +++--- 24 files changed, 273 insertions(+), 261 deletions(-) create mode 100644 src/core/hle/kernel/synchronization_object.cpp create mode 100644 src/core/hle/kernel/synchronization_object.h delete mode 100644 src/core/hle/kernel/wait_object.cpp delete mode 100644 src/core/hle/kernel/wait_object.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d342cafe0..052907f08 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -181,14 +181,14 @@ add_library(core STATIC hle/kernel/svc.cpp hle/kernel/svc.h hle/kernel/svc_wrap.h + hle/kernel/synchronization_object.cpp + hle/kernel/synchronization_object.h hle/kernel/thread.cpp hle/kernel/thread.h hle/kernel/transfer_memory.cpp hle/kernel/transfer_memory.h hle/kernel/vm_manager.cpp hle/kernel/vm_manager.h - hle/kernel/wait_object.cpp - hle/kernel/wait_object.h hle/kernel/writable_event.cpp hle/kernel/writable_event.h hle/lock.cpp diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 4669a14ad..3dfeb9813 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -12,7 +12,7 @@ namespace Kernel { -ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {} +ClientSession::ClientSession(KernelCore& kernel) : SynchronizationObject{kernel} {} ClientSession::~ClientSession() { // This destructor will be called automatically when the last ClientSession handle is closed by diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index b4289a9a8..9cf9219b1 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -7,7 +7,7 @@ #include #include -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" union ResultCode; @@ -22,7 +22,7 @@ class KernelCore; class Session; class Thread; -class ClientSession final : public WaitObject { +class ClientSession final : public SynchronizationObject { public: explicit ClientSession(KernelCore& kernel); ~ClientSession() override; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index ab05788d7..c558a2f33 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -47,15 +47,15 @@ std::shared_ptr HLERequestContext::SleepClientThread( const std::string& reason, u64 timeout, WakeupCallback&& callback, std::shared_ptr writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->SetWakeupCallback([context = *this, callback](ThreadWakeupReason reason, - std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) mutable -> bool { - ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); - callback(thread, context, reason); - context.WriteToOutgoingCommandBuffer(*thread); - return true; - }); + thread->SetWakeupCallback( + [context = *this, callback](ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object, + std::size_t index) mutable -> bool { + ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); + callback(thread, context, reason); + context.WriteToOutgoingCommandBuffer(*thread); + return true; + }); auto& kernel = Core::System::GetInstance().Kernel(); if (!writable_event) { @@ -67,7 +67,7 @@ std::shared_ptr HLERequestContext::SleepClientThread( const auto readable_event{writable_event->GetReadableEvent()}; writable_event->Clear(); thread->SetStatus(ThreadStatus::WaitHLEEvent); - thread->SetWaitObjects({readable_event}); + thread->SetSynchronizationObjects({readable_event}); readable_event->AddWaitingThread(thread); if (timeout > 0) { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index edd4c4259..26799f6b5 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -54,10 +54,10 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ if (thread->GetStatus() == ThreadStatus::WaitSynch || thread->GetStatus() == ThreadStatus::WaitHLEEvent) { // Remove the thread from each of its waiting objects' waitlists - for (const auto& object : thread->GetWaitObjects()) { + for (const auto& object : thread->GetSynchronizationObjects()) { object->RemoveWaitingThread(thread); } - thread->ClearWaitObjects(); + thread->ClearSynchronizationObjects(); // Invoke the wakeup callback before clearing the wait objects if (thread->HasWakeupCallback()) { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index b9035a0be..7a616435a 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -337,7 +337,7 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { } Process::Process(Core::System& system) - : WaitObject{system.Kernel()}, vm_manager{system}, + : SynchronizationObject{system.Kernel()}, vm_manager{system}, address_arbiter{system}, mutex{system}, system{system} {} Process::~Process() = default; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 3483fa19d..7b64c564a 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -15,8 +15,8 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process_capability.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/kernel/vm_manager.h" -#include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" namespace Core { @@ -60,7 +60,7 @@ enum class ProcessStatus { DebugBreak, }; -class Process final : public WaitObject { +class Process final : public SynchronizationObject { public: explicit Process(Core::System& system); ~Process() override; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index d8ac97aa1..8ab796ba8 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -11,7 +11,7 @@ namespace Kernel { -ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {} +ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} {} ReadableEvent::~ReadableEvent() = default; bool ReadableEvent::ShouldWait(const Thread* thread) const { diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index 11ff71c3a..c7b0d6add 100644 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h @@ -5,7 +5,7 @@ #pragma once #include "core/hle/kernel/object.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" union ResultCode; @@ -14,7 +14,7 @@ namespace Kernel { class KernelCore; class WritableEvent; -class ReadableEvent final : public WaitObject { +class ReadableEvent final : public SynchronizationObject { friend class WritableEvent; public: diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index a4ccfa35e..4f02f8df2 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {} +ServerPort::ServerPort(KernelCore& kernel) : SynchronizationObject{kernel} {} ServerPort::~ServerPort() = default; ResultVal> ServerPort::Accept() { diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 8be8a75ea..43cf3ae18 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -10,7 +10,7 @@ #include #include "common/common_types.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" namespace Kernel { @@ -20,7 +20,7 @@ class KernelCore; class ServerSession; class SessionRequestHandler; -class ServerPort final : public WaitObject { +class ServerPort final : public SynchronizationObject { public: explicit ServerPort(KernelCore& kernel); ~ServerPort() override; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 7825e1ec4..8207f71c3 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -24,7 +24,7 @@ namespace Kernel { -ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} +ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {} ServerSession::~ServerSession() = default; ResultVal> ServerSession::Create(KernelCore& kernel, diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index d6e48109e..3688c7d11 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -10,7 +10,7 @@ #include #include "common/threadsafe_queue.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" namespace Memory { @@ -41,7 +41,7 @@ class Thread; * After the server replies to the request, the response is marshalled back to the caller's * TLS buffer and control is transferred back to it. */ -class ServerSession final : public WaitObject { +class ServerSession final : public SynchronizationObject { public: explicit ServerSession(KernelCore& kernel); ~ServerSession() override; diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index dee6e2b72..1c1fc440d 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp @@ -9,7 +9,7 @@ namespace Kernel { -Session::Session(KernelCore& kernel) : WaitObject{kernel} {} +Session::Session(KernelCore& kernel) : SynchronizationObject{kernel} {} Session::~Session() = default; Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 15a5ac15f..d107dd9aa 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -8,7 +8,7 @@ #include #include -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" namespace Kernel { @@ -19,7 +19,7 @@ class ServerSession; * Parent structure to link the client and server endpoints of a session with their associated * client port. */ -class Session final : public WaitObject { +class Session final : public SynchronizationObject { public: explicit Session(KernelCore& kernel); ~Session() override; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9cae5c73d..39552a176 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -435,7 +435,8 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han /// Default thread wakeup callback for WaitSynchronization static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index) { + std::shared_ptr object, + std::size_t index) { ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); if (reason == ThreadWakeupReason::Timeout) { @@ -473,13 +474,13 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr auto* const thread = system.CurrentScheduler().GetCurrentThread(); - using ObjectPtr = Thread::ThreadWaitObjects::value_type; - Thread::ThreadWaitObjects objects(handle_count); + using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type; + Thread::ThreadSynchronizationObjects objects(handle_count); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); for (u64 i = 0; i < handle_count; ++i) { const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); - const auto object = handle_table.Get(handle); + const auto object = handle_table.Get(handle); if (object == nullptr) { LOG_ERROR(Kernel_SVC, "Object is a nullptr"); @@ -496,7 +497,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr if (itr != objects.end()) { // We found a ready object, acquire it and set the result value - WaitObject* object = itr->get(); + SynchronizationObject* object = itr->get(); object->Acquire(thread); *index = static_cast(std::distance(objects.begin(), itr)); return RESULT_SUCCESS; @@ -519,7 +520,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr object->AddWaitingThread(SharedFrom(thread)); } - thread->SetWaitObjects(std::move(objects)); + thread->SetSynchronizationObjects(std::move(objects)); thread->SetStatus(ThreadStatus::WaitSynch); // Create an event to wake the thread up after the specified nanosecond delay has passed diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp new file mode 100644 index 000000000..95f3f9245 --- /dev/null +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -0,0 +1,104 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "common/assert.h" +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/synchronization_object.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {} +SynchronizationObject::~SynchronizationObject() = default; + +void SynchronizationObject::AddWaitingThread(std::shared_ptr thread) { + auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); + if (itr == waiting_threads.end()) + waiting_threads.push_back(std::move(thread)); +} + +void SynchronizationObject::RemoveWaitingThread(std::shared_ptr thread) { + auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); + // If a thread passed multiple handles to the same object, + // the kernel might attempt to remove the thread from the object's + // waiting threads list multiple times. + if (itr != waiting_threads.end()) + waiting_threads.erase(itr); +} + +std::shared_ptr SynchronizationObject::GetHighestPriorityReadyThread() const { + Thread* candidate = nullptr; + u32 candidate_priority = THREADPRIO_LOWEST + 1; + + for (const auto& thread : waiting_threads) { + const ThreadStatus thread_status = thread->GetStatus(); + + // The list of waiting threads must not contain threads that are not waiting to be awakened. + ASSERT_MSG(thread_status == ThreadStatus::WaitSynch || + thread_status == ThreadStatus::WaitHLEEvent, + "Inconsistent thread statuses in waiting_threads"); + + if (thread->GetPriority() >= candidate_priority) + continue; + + if (ShouldWait(thread.get())) + continue; + + candidate = thread.get(); + candidate_priority = thread->GetPriority(); + } + + return SharedFrom(candidate); +} + +void SynchronizationObject::WakeupWaitingThread(std::shared_ptr thread) { + ASSERT(!ShouldWait(thread.get())); + + if (!thread) { + return; + } + + if (thread->IsSleepingOnWait()) { + for (const auto& object : thread->GetSynchronizationObjects()) { + ASSERT(!object->ShouldWait(thread.get())); + object->Acquire(thread.get()); + } + } else { + Acquire(thread.get()); + } + + const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this)); + + thread->ClearSynchronizationObjects(); + + thread->CancelWakeupTimer(); + + bool resume = true; + if (thread->HasWakeupCallback()) { + resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this), + index); + } + if (resume) { + thread->ResumeFromWait(); + kernel.PrepareReschedule(thread->GetProcessorID()); + } +} + +void SynchronizationObject::WakeupAllWaitingThreads() { + while (auto thread = GetHighestPriorityReadyThread()) { + WakeupWaitingThread(thread); + } +} + +const std::vector>& SynchronizationObject::GetWaitingThreads() const { + return waiting_threads; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h new file mode 100644 index 000000000..a0f891c97 --- /dev/null +++ b/src/core/hle/kernel/synchronization_object.h @@ -0,0 +1,78 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "core/hle/kernel/object.h" + +namespace Kernel { + +class KernelCore; +class Thread; + +/// Class that represents a Kernel object that a thread can be waiting on +class SynchronizationObject : public Object { +public: + explicit SynchronizationObject(KernelCore& kernel); + ~SynchronizationObject() override; + + /** + * Check if the specified thread should wait until the object is available + * @param thread The thread about which we're deciding. + * @return True if the current thread should wait due to this object being unavailable + */ + virtual bool ShouldWait(const Thread* thread) const = 0; + + /// Acquire/lock the object for the specified thread if it is available + virtual void Acquire(Thread* thread) = 0; + + /** + * Add a thread to wait on this object + * @param thread Pointer to thread to add + */ + void AddWaitingThread(std::shared_ptr thread); + + /** + * Removes a thread from waiting on this object (e.g. if it was resumed already) + * @param thread Pointer to thread to remove + */ + void RemoveWaitingThread(std::shared_ptr thread); + + /** + * Wake up all threads waiting on this object that can be awoken, in priority order, + * and set the synchronization result and output of the thread. + */ + void WakeupAllWaitingThreads(); + + /** + * Wakes up a single thread waiting on this object. + * @param thread Thread that is waiting on this object to wakeup. + */ + void WakeupWaitingThread(std::shared_ptr thread); + + /// Obtains the highest priority thread that is ready to run from this object's waiting list. + std::shared_ptr GetHighestPriorityReadyThread() const; + + /// Get a const reference to the waiting threads list for debug use + const std::vector>& GetWaitingThreads() const; + +private: + /// Threads waiting for this object to become available + std::vector> waiting_threads; +}; + +// Specialization of DynamicObjectCast for SynchronizationObjects +template <> +inline std::shared_ptr DynamicObjectCast( + std::shared_ptr object) { + if (object != nullptr && object->IsWaitable()) { + return std::static_pointer_cast(object); + } + return nullptr; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e965b5b04..0f096ed6d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -35,7 +35,7 @@ void Thread::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } -Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {} +Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {} Thread::~Thread() = default; void Thread::Stop() { @@ -215,7 +215,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { context.cpu_registers[1] = output; } -s32 Thread::GetWaitObjectIndex(std::shared_ptr object) const { +s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr object) const { ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); return static_cast(std::distance(match, wait_objects.rend()) - 1); @@ -336,14 +336,16 @@ void Thread::ChangeCore(u32 core, u64 mask) { SetCoreAndAffinityMask(core, mask); } -bool Thread::AllWaitObjectsReady() const { - return std::none_of( - wait_objects.begin(), wait_objects.end(), - [this](const std::shared_ptr& object) { return object->ShouldWait(this); }); +bool Thread::AllSynchronizationObjectsReady() const { + return std::none_of(wait_objects.begin(), wait_objects.end(), + [this](const std::shared_ptr& object) { + return object->ShouldWait(this); + }); } bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index) { + std::shared_ptr object, + std::size_t index) { ASSERT(wakeup_callback); return wakeup_callback(reason, std::move(thread), std::move(object), index); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 3bcf9e137..895258095 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" namespace Kernel { @@ -95,7 +95,7 @@ enum class ThreadSchedMasks : u32 { ForcePauseMask = 0x0070, }; -class Thread final : public WaitObject { +class Thread final : public SynchronizationObject { public: explicit Thread(KernelCore& kernel); ~Thread() override; @@ -104,11 +104,11 @@ public: using ThreadContext = Core::ARM_Interface::ThreadContext; - using ThreadWaitObjects = std::vector>; + using ThreadSynchronizationObjects = std::vector>; using WakeupCallback = std::function thread, - std::shared_ptr object, std::size_t index)>; + std::shared_ptr object, std::size_t index)>; /** * Creates and returns a new thread. The new thread is immediately scheduled @@ -233,7 +233,7 @@ public: * * @param object Object to query the index of. */ - s32 GetWaitObjectIndex(std::shared_ptr object) const; + s32 GetSynchronizationObjectIndex(std::shared_ptr object) const; /** * Stops a thread, invalidating it from further use @@ -314,15 +314,15 @@ public: return owner_process; } - const ThreadWaitObjects& GetWaitObjects() const { + const ThreadSynchronizationObjects& GetSynchronizationObjects() const { return wait_objects; } - void SetWaitObjects(ThreadWaitObjects objects) { + void SetSynchronizationObjects(ThreadSynchronizationObjects objects) { wait_objects = std::move(objects); } - void ClearWaitObjects() { + void ClearSynchronizationObjects() { for (const auto& waiting_object : wait_objects) { waiting_object->RemoveWaitingThread(SharedFrom(this)); } @@ -330,7 +330,7 @@ public: } /// Determines whether all the objects this thread is waiting on are ready. - bool AllWaitObjectsReady() const; + bool AllSynchronizationObjectsReady() const; const MutexWaitingThreads& GetMutexWaitingThreads() const { return wait_mutex_threads; @@ -395,7 +395,7 @@ public: * will cause an assertion to trigger. */ bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index); + std::shared_ptr object, std::size_t index); u32 GetIdealCore() const { return ideal_core; @@ -494,7 +494,7 @@ private: /// Objects that the thread is waiting on, in the same order as they were /// passed to WaitSynchronization. - ThreadWaitObjects wait_objects; + ThreadSynchronizationObjects wait_objects; /// List of threads that are waiting for a mutex that is held by this thread. MutexWaitingThreads wait_mutex_threads; diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp deleted file mode 100644 index 1838260fd..000000000 --- a/src/core/hle/kernel/wait_object.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/assert.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/core.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/thread.h" - -namespace Kernel { - -WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {} -WaitObject::~WaitObject() = default; - -void WaitObject::AddWaitingThread(std::shared_ptr thread) { - auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); - if (itr == waiting_threads.end()) - waiting_threads.push_back(std::move(thread)); -} - -void WaitObject::RemoveWaitingThread(std::shared_ptr thread) { - auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); - // If a thread passed multiple handles to the same object, - // the kernel might attempt to remove the thread from the object's - // waiting threads list multiple times. - if (itr != waiting_threads.end()) - waiting_threads.erase(itr); -} - -std::shared_ptr WaitObject::GetHighestPriorityReadyThread() const { - Thread* candidate = nullptr; - u32 candidate_priority = THREADPRIO_LOWEST + 1; - - for (const auto& thread : waiting_threads) { - const ThreadStatus thread_status = thread->GetStatus(); - - // The list of waiting threads must not contain threads that are not waiting to be awakened. - ASSERT_MSG(thread_status == ThreadStatus::WaitSynch || - thread_status == ThreadStatus::WaitHLEEvent, - "Inconsistent thread statuses in waiting_threads"); - - if (thread->GetPriority() >= candidate_priority) - continue; - - if (ShouldWait(thread.get())) - continue; - - candidate = thread.get(); - candidate_priority = thread->GetPriority(); - } - - return SharedFrom(candidate); -} - -void WaitObject::WakeupWaitingThread(std::shared_ptr thread) { - ASSERT(!ShouldWait(thread.get())); - - if (!thread) { - return; - } - - if (thread->IsSleepingOnWait()) { - for (const auto& object : thread->GetWaitObjects()) { - ASSERT(!object->ShouldWait(thread.get())); - object->Acquire(thread.get()); - } - } else { - Acquire(thread.get()); - } - - const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this)); - - thread->ClearWaitObjects(); - - thread->CancelWakeupTimer(); - - bool resume = true; - if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this), - index); - } - if (resume) { - thread->ResumeFromWait(); - kernel.PrepareReschedule(thread->GetProcessorID()); - } -} - -void WaitObject::WakeupAllWaitingThreads() { - while (auto thread = GetHighestPriorityReadyThread()) { - WakeupWaitingThread(thread); - } -} - -const std::vector>& WaitObject::GetWaitingThreads() const { - return waiting_threads; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h deleted file mode 100644 index 9a17958a4..000000000 --- a/src/core/hle/kernel/wait_object.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -#include "core/hle/kernel/object.h" - -namespace Kernel { - -class KernelCore; -class Thread; - -/// Class that represents a Kernel object that a thread can be waiting on -class WaitObject : public Object { -public: - explicit WaitObject(KernelCore& kernel); - ~WaitObject() override; - - /** - * Check if the specified thread should wait until the object is available - * @param thread The thread about which we're deciding. - * @return True if the current thread should wait due to this object being unavailable - */ - virtual bool ShouldWait(const Thread* thread) const = 0; - - /// Acquire/lock the object for the specified thread if it is available - virtual void Acquire(Thread* thread) = 0; - - /** - * Add a thread to wait on this object - * @param thread Pointer to thread to add - */ - void AddWaitingThread(std::shared_ptr thread); - - /** - * Removes a thread from waiting on this object (e.g. if it was resumed already) - * @param thread Pointer to thread to remove - */ - void RemoveWaitingThread(std::shared_ptr thread); - - /** - * Wake up all threads waiting on this object that can be awoken, in priority order, - * and set the synchronization result and output of the thread. - */ - void WakeupAllWaitingThreads(); - - /** - * Wakes up a single thread waiting on this object. - * @param thread Thread that is waiting on this object to wakeup. - */ - void WakeupWaitingThread(std::shared_ptr thread); - - /// Obtains the highest priority thread that is ready to run from this object's waiting list. - std::shared_ptr GetHighestPriorityReadyThread() const; - - /// Get a const reference to the waiting threads list for debug use - const std::vector>& GetWaitingThreads() const; - -private: - /// Threads waiting for this object to become available - std::vector> waiting_threads; -}; - -// Specialization of DynamicObjectCast for WaitObjects -template <> -inline std::shared_ptr DynamicObjectCast(std::shared_ptr object) { - if (object != nullptr && object->IsWaitable()) { - return std::static_pointer_cast(object); - } - return nullptr; -} - -} // namespace Kernel diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 727bd8a94..3f1a94627 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -12,8 +12,8 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/synchronization_object.h" #include "core/hle/kernel/thread.h" -#include "core/hle/kernel/wait_object.h" #include "core/memory.h" WaitTreeItem::WaitTreeItem() = default; @@ -133,8 +133,9 @@ std::vector> WaitTreeCallstack::GetChildren() cons return list; } -WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {} -WaitTreeWaitObject::~WaitTreeWaitObject() = default; +WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& o) + : object(o) {} +WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default; WaitTreeExpandableItem::WaitTreeExpandableItem() = default; WaitTreeExpandableItem::~WaitTreeExpandableItem() = default; @@ -143,25 +144,26 @@ bool WaitTreeExpandableItem::IsExpandable() const { return true; } -QString WaitTreeWaitObject::GetText() const { +QString WaitTreeSynchronizationObject::GetText() const { return tr("[%1]%2 %3") .arg(object.GetObjectId()) .arg(QString::fromStdString(object.GetTypeName()), QString::fromStdString(object.GetName())); } -std::unique_ptr WaitTreeWaitObject::make(const Kernel::WaitObject& object) { +std::unique_ptr WaitTreeSynchronizationObject::make( + const Kernel::SynchronizationObject& object) { switch (object.GetHandleType()) { case Kernel::HandleType::ReadableEvent: return std::make_unique(static_cast(object)); case Kernel::HandleType::Thread: return std::make_unique(static_cast(object)); default: - return std::make_unique(object); + return std::make_unique(object); } } -std::vector> WaitTreeWaitObject::GetChildren() const { +std::vector> WaitTreeSynchronizationObject::GetChildren() const { std::vector> list; const auto& threads = object.GetWaitingThreads(); @@ -173,8 +175,8 @@ std::vector> WaitTreeWaitObject::GetChildren() con return list; } -WaitTreeObjectList::WaitTreeObjectList(const std::vector>& list, - bool w_all) +WaitTreeObjectList::WaitTreeObjectList( + const std::vector>& list, bool w_all) : object_list(list), wait_all(w_all) {} WaitTreeObjectList::~WaitTreeObjectList() = default; @@ -188,11 +190,12 @@ QString WaitTreeObjectList::GetText() const { std::vector> WaitTreeObjectList::GetChildren() const { std::vector> list(object_list.size()); std::transform(object_list.begin(), object_list.end(), list.begin(), - [](const auto& t) { return WaitTreeWaitObject::make(*t); }); + [](const auto& t) { return WaitTreeSynchronizationObject::make(*t); }); return list; } -WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread) : WaitTreeWaitObject(thread) {} +WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread) + : WaitTreeSynchronizationObject(thread) {} WaitTreeThread::~WaitTreeThread() = default; QString WaitTreeThread::GetText() const { @@ -241,7 +244,8 @@ QString WaitTreeThread::GetText() const { const QString pc_info = tr(" PC = 0x%1 LR = 0x%2") .arg(context.pc, 8, 16, QLatin1Char{'0'}) .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'}); - return QStringLiteral("%1%2 (%3) ").arg(WaitTreeWaitObject::GetText(), pc_info, status); + return QStringLiteral("%1%2 (%3) ") + .arg(WaitTreeSynchronizationObject::GetText(), pc_info, status); } QColor WaitTreeThread::GetColor() const { @@ -273,7 +277,7 @@ QColor WaitTreeThread::GetColor() const { } std::vector> WaitTreeThread::GetChildren() const { - std::vector> list(WaitTreeWaitObject::GetChildren()); + std::vector> list(WaitTreeSynchronizationObject::GetChildren()); const auto& thread = static_cast(object); @@ -314,7 +318,7 @@ std::vector> WaitTreeThread::GetChildren() const { } if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { - list.push_back(std::make_unique(thread.GetWaitObjects(), + list.push_back(std::make_unique(thread.GetSynchronizationObjects(), thread.IsSleepingOnWait())); } @@ -323,7 +327,8 @@ std::vector> WaitTreeThread::GetChildren() const { return list; } -WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeWaitObject(object) {} +WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) + : WaitTreeSynchronizationObject(object) {} WaitTreeEvent::~WaitTreeEvent() = default; WaitTreeThreadList::WaitTreeThreadList(const std::vector>& list) diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h index 631274a5f..8e3bc4b24 100644 --- a/src/yuzu/debugger/wait_tree.h +++ b/src/yuzu/debugger/wait_tree.h @@ -19,7 +19,7 @@ class EmuThread; namespace Kernel { class HandleTable; class ReadableEvent; -class WaitObject; +class SynchronizationObject; class Thread; } // namespace Kernel @@ -99,35 +99,37 @@ private: const Kernel::Thread& thread; }; -class WaitTreeWaitObject : public WaitTreeExpandableItem { +class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { Q_OBJECT public: - explicit WaitTreeWaitObject(const Kernel::WaitObject& object); - ~WaitTreeWaitObject() override; + explicit WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& object); + ~WaitTreeSynchronizationObject() override; - static std::unique_ptr make(const Kernel::WaitObject& object); + static std::unique_ptr make( + const Kernel::SynchronizationObject& object); QString GetText() const override; std::vector> GetChildren() const override; protected: - const Kernel::WaitObject& object; + const Kernel::SynchronizationObject& object; }; class WaitTreeObjectList : public WaitTreeExpandableItem { Q_OBJECT public: - WaitTreeObjectList(const std::vector>& list, bool wait_all); + WaitTreeObjectList(const std::vector>& list, + bool wait_all); ~WaitTreeObjectList() override; QString GetText() const override; std::vector> GetChildren() const override; private: - const std::vector>& object_list; + const std::vector>& object_list; bool wait_all; }; -class WaitTreeThread : public WaitTreeWaitObject { +class WaitTreeThread : public WaitTreeSynchronizationObject { Q_OBJECT public: explicit WaitTreeThread(const Kernel::Thread& thread); @@ -138,7 +140,7 @@ public: std::vector> GetChildren() const override; }; -class WaitTreeEvent : public WaitTreeWaitObject { +class WaitTreeEvent : public WaitTreeSynchronizationObject { Q_OBJECT public: explicit WaitTreeEvent(const Kernel::ReadableEvent& object); -- cgit v1.2.3