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 ------------------ 22 files changed, 241 insertions(+), 236 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/core') 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 -- cgit v1.2.3 From d23d504d776007c1244a85ac1b7bb67c407067b2 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 11 Feb 2020 17:36:39 -0400 Subject: Kernel: Refactor synchronization to better match RE --- src/core/CMakeLists.txt | 2 + src/core/hle/kernel/client_session.cpp | 5 ++ src/core/hle/kernel/client_session.h | 2 + src/core/hle/kernel/kernel.cpp | 13 +++- src/core/hle/kernel/kernel.h | 7 +++ src/core/hle/kernel/process.cpp | 2 +- src/core/hle/kernel/process.h | 4 -- src/core/hle/kernel/readable_event.cpp | 14 ++--- src/core/hle/kernel/readable_event.h | 6 +- src/core/hle/kernel/server_port.cpp | 4 ++ src/core/hle/kernel/server_port.h | 2 + src/core/hle/kernel/server_session.cpp | 10 +++ src/core/hle/kernel/server_session.h | 2 + src/core/hle/kernel/session.cpp | 5 ++ src/core/hle/kernel/session.h | 2 + src/core/hle/kernel/svc.cpp | 67 +++----------------- src/core/hle/kernel/synchronization.cpp | 86 ++++++++++++++++++++++++++ src/core/hle/kernel/synchronization.h | 34 ++++++++++ src/core/hle/kernel/synchronization_object.cpp | 5 ++ src/core/hle/kernel/synchronization_object.h | 10 +++ src/core/hle/kernel/thread.cpp | 6 +- src/core/hle/kernel/thread.h | 1 + src/core/hle/kernel/writable_event.cpp | 3 +- 23 files changed, 212 insertions(+), 80 deletions(-) create mode 100644 src/core/hle/kernel/synchronization.cpp create mode 100644 src/core/hle/kernel/synchronization.h (limited to 'src/core') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 052907f08..26612e692 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -183,6 +183,8 @@ add_library(core STATIC hle/kernel/svc_wrap.h hle/kernel/synchronization_object.cpp hle/kernel/synchronization_object.h + hle/kernel/synchronization.cpp + hle/kernel/synchronization.h hle/kernel/thread.cpp hle/kernel/thread.h hle/kernel/transfer_memory.cpp diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 3dfeb9813..6d66276bc 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -31,6 +31,11 @@ void ClientSession::Acquire(Thread* thread) { UNIMPLEMENTED(); } +bool ClientSession::IsSignaled() const { + UNIMPLEMENTED(); + return true; +} + ResultVal> ClientSession::Create(KernelCore& kernel, std::shared_ptr parent, std::string name) { diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 9cf9219b1..d15b09554 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -48,6 +48,8 @@ public: void Acquire(Thread* thread) override; + bool IsSignaled() const override; + private: static ResultVal> Create(KernelCore& kernel, std::shared_ptr parent, diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 26799f6b5..4eb1d8703 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -23,6 +23,7 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/thread.h" #include "core/hle/lock.h" #include "core/hle/result.h" @@ -96,7 +97,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ } struct KernelCore::Impl { - explicit Impl(Core::System& system) : system{system}, global_scheduler{system} {} + explicit Impl(Core::System& system) + : system{system}, global_scheduler{system}, synchronization{system} {} void Initialize(KernelCore& kernel) { Shutdown(); @@ -191,6 +193,7 @@ struct KernelCore::Impl { std::vector> process_list; Process* current_process = nullptr; Kernel::GlobalScheduler global_scheduler; + Kernel::Synchronization synchronization; std::shared_ptr system_resource_limit; @@ -270,6 +273,14 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { return impl->cores[id]; } +Kernel::Synchronization& KernelCore::Synchronization() { + return impl->synchronization; +} + +const Kernel::Synchronization& KernelCore::Synchronization() const { + return impl->synchronization; +} + Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { return *impl->exclusive_monitor; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index fccffaf3a..1eede3063 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -29,6 +29,7 @@ class HandleTable; class PhysicalCore; class Process; class ResourceLimit; +class Synchronization; class Thread; /// Represents a single instance of the kernel. @@ -92,6 +93,12 @@ public: /// Gets the an instance of the respective physical CPU core. const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; + /// Gets the an instance of the Synchronization Interface. + Kernel::Synchronization& Synchronization(); + + /// Gets the an instance of the Synchronization Interface. + const Kernel::Synchronization& Synchronization() const; + /// Stops execution of 'id' core, in order to reschedule a new thread. void PrepareReschedule(std::size_t id); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 7a616435a..2fcb7326c 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -357,7 +357,7 @@ void Process::ChangeStatus(ProcessStatus new_status) { status = new_status; is_signaled = true; - WakeupAllWaitingThreads(); + Signal(); } void Process::AllocateMainThreadStack(u64 stack_size) { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 7b64c564a..4887132a7 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -359,10 +359,6 @@ private: /// specified by metadata provided to the process during loading. bool is_64bit_process = true; - /// Whether or not this process is signaled. This occurs - /// upon the process changing to a different state. - bool is_signaled = false; - /// Total running time for the process in ticks. u64 total_process_running_time_ticks = 0; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index 8ab796ba8..9d3d3a81b 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -15,26 +15,26 @@ ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} ReadableEvent::~ReadableEvent() = default; bool ReadableEvent::ShouldWait(const Thread* thread) const { - return !signaled; + return !is_signaled; } void ReadableEvent::Acquire(Thread* thread) { - ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); + ASSERT_MSG(IsSignaled(), "object unavailable!"); } void ReadableEvent::Signal() { - if (!signaled) { - signaled = true; - WakeupAllWaitingThreads(); + if (!is_signaled) { + is_signaled = true; + SynchronizationObject::Signal(); }; } void ReadableEvent::Clear() { - signaled = false; + is_signaled = false; } ResultCode ReadableEvent::Reset() { - if (!signaled) { + if (!is_signaled) { return ERR_INVALID_STATE; } diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index c7b0d6add..3264dd066 100644 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h @@ -46,13 +46,11 @@ public: /// then ERR_INVALID_STATE will be returned. ResultCode Reset(); + void Signal() override; + private: explicit ReadableEvent(KernelCore& kernel); - void Signal(); - - bool signaled{}; - std::string name; ///< Name of event (optional) }; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 4f02f8df2..a549ae9d7 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -39,6 +39,10 @@ void ServerPort::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } +bool ServerPort::IsSignaled() const { + return !pending_sessions.empty(); +} + ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, std::string name) { std::shared_ptr server_port = std::make_shared(kernel); diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 43cf3ae18..41b191b86 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -82,6 +82,8 @@ public: bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; + bool IsSignaled() const override; + private: /// ServerSessions waiting to be accepted by the port std::vector> pending_sessions; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 8207f71c3..ca98fd984 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -50,6 +50,16 @@ bool ServerSession::ShouldWait(const Thread* thread) const { return pending_requesting_threads.empty() || currently_handling != nullptr; } +bool ServerSession::IsSignaled() const { + // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. + if (!parent->Client()) { + return true; + } + + // Wait if we have no pending requests, or if we're currently handling a request. + return !(pending_requesting_threads.empty() || currently_handling != nullptr); +} + void ServerSession::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); // We are now handling a request, pop it from the stack. diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 3688c7d11..77e4f6721 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -73,6 +73,8 @@ public: return parent.get(); } + bool IsSignaled() const override; + /** * Sets the HLE handler for the session. This handler will be called to service IPC requests * instead of the regular IPC machinery. (The regular IPC machinery is currently not diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index 1c1fc440d..e4dd53e24 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp @@ -29,6 +29,11 @@ bool Session::ShouldWait(const Thread* thread) const { return {}; } +bool Session::IsSignaled() const { + UNIMPLEMENTED(); + return true; +} + void Session::Acquire(Thread* thread) { UNIMPLEMENTED(); } diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index d107dd9aa..7cd9c0d77 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -39,6 +39,8 @@ public: bool ShouldWait(const Thread* thread) const override; + bool IsSignaled() const override; + void Acquire(Thread* thread) override; std::shared_ptr Client() { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 39552a176..86c660cdf 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -32,6 +32,7 @@ #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_wrap.h" +#include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/transfer_memory.h" #include "core/hle/kernel/writable_event.h" @@ -433,23 +434,6 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han return ERR_INVALID_HANDLE; } -/// Default thread wakeup callback for WaitSynchronization -static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); - - if (reason == ThreadWakeupReason::Timeout) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - return true; - } - - ASSERT(reason == ThreadWakeupReason::Signal); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - thread->SetWaitSynchronizationOutput(static_cast(index)); - return true; -}; - /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, u64 handle_count, s64 nano_seconds) { @@ -473,10 +457,10 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr } auto* const thread = system.CurrentScheduler().GetCurrentThread(); - + auto& kernel = system.Kernel(); using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type; Thread::ThreadSynchronizationObjects objects(handle_count); - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); for (u64 i = 0; i < handle_count; ++i) { const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); @@ -489,47 +473,10 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr objects[i] = object; } - - // Find the first object that is acquirable in the provided list of objects - auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { - return !object->ShouldWait(thread); - }); - - if (itr != objects.end()) { - // We found a ready object, acquire it and set the result value - SynchronizationObject* object = itr->get(); - object->Acquire(thread); - *index = static_cast(std::distance(objects.begin(), itr)); - return RESULT_SUCCESS; - } - - // No objects were ready to be acquired, prepare to suspend the thread. - - // If a timeout value of 0 was provided, just return the Timeout error code instead of - // suspending the thread. - if (nano_seconds == 0) { - return RESULT_TIMEOUT; - } - - if (thread->IsSyncCancelled()) { - thread->SetSyncCancelled(false); - return ERR_SYNCHRONIZATION_CANCELED; - } - - for (auto& object : objects) { - object->AddWaitingThread(SharedFrom(thread)); - } - - thread->SetSynchronizationObjects(std::move(objects)); - thread->SetStatus(ThreadStatus::WaitSynch); - - // Create an event to wake the thread up after the specified nanosecond delay has passed - thread->WakeAfterDelay(nano_seconds); - thread->SetWakeupCallback(DefaultThreadWakeupCallback); - - system.PrepareReschedule(thread->GetProcessorID()); - - return RESULT_TIMEOUT; + auto& synchronization = kernel.Synchronization(); + auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds); + *index = handle_result; + return result; } /// Resumes a thread waiting on WaitSynchronization diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp new file mode 100644 index 000000000..25afc162f --- /dev/null +++ b/src/core/hle/kernel/synchronization.cpp @@ -0,0 +1,86 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/synchronization.h" +#include "core/hle/kernel/synchronization_object.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +/// Default thread wakeup callback for WaitSynchronization +static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object, + std::size_t index) { + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); + + if (reason == ThreadWakeupReason::Timeout) { + thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); + return true; + } + + ASSERT(reason == ThreadWakeupReason::Signal); + thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + thread->SetWaitSynchronizationOutput(static_cast(index)); + return true; +}; + +Synchronization::Synchronization(Core::System& system) : system{system} {} + +void Synchronization::SignalObject(SynchronizationObject& obj) const { + if (obj.IsSignaled()) { + obj.WakeupAllWaitingThreads(); + }; +} + +std::pair Synchronization::WaitFor( + std::vector>& sync_objects, s64 nano_seconds) { + auto* const thread = system.CurrentScheduler().GetCurrentThread(); + // Find the first object that is acquirable in the provided list of objects + auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), + [thread](const std::shared_ptr& object) { + return object->IsSignaled(); + }); + + if (itr != sync_objects.end()) { + // We found a ready object, acquire it and set the result value + SynchronizationObject* object = itr->get(); + object->Acquire(thread); + u32 index = static_cast(std::distance(sync_objects.begin(), itr)); + return {RESULT_SUCCESS, index}; + } + + // No objects were ready to be acquired, prepare to suspend the thread. + + // If a timeout value of 0 was provided, just return the Timeout error code instead of + // suspending the thread. + if (nano_seconds == 0) { + return {RESULT_TIMEOUT, 0}; + } + + if (thread->IsSyncCancelled()) { + thread->SetSyncCancelled(false); + return {ERR_SYNCHRONIZATION_CANCELED, 0}; + } + + for (auto& object : sync_objects) { + object->AddWaitingThread(SharedFrom(thread)); + } + + thread->SetSynchronizationObjects(std::move(sync_objects)); + thread->SetStatus(ThreadStatus::WaitSynch); + + // Create an event to wake the thread up after the specified nanosecond delay has passed + thread->WakeAfterDelay(nano_seconds); + thread->SetWakeupCallback(DefaultThreadWakeupCallback); + + system.PrepareReschedule(thread->GetProcessorID()); + + return {RESULT_TIMEOUT, 0}; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/synchronization.h b/src/core/hle/kernel/synchronization.h new file mode 100644 index 000000000..3417a9f13 --- /dev/null +++ b/src/core/hle/kernel/synchronization.h @@ -0,0 +1,34 @@ +// Copyright 2020 yuzu 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" +#include "core/hle/result.h" + +namespace Core { +class System; +} // namespace Core + +namespace Kernel { + +class KernelCore; +class SynchronizationObject; + +class Synchronization { +public: + Synchronization(Core::System& system); + + void SignalObject(SynchronizationObject& obj) const; + + std::pair WaitFor( + std::vector>& sync_objects, s64 nano_seconds); + +private: + Core::System& system; +}; +} // namespace Kernel diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index 95f3f9245..43f3eef18 100644 --- a/src/core/hle/kernel/synchronization_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -10,6 +10,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/synchronization_object.h" #include "core/hle/kernel/thread.h" @@ -18,6 +19,10 @@ namespace Kernel { SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {} SynchronizationObject::~SynchronizationObject() = default; +void SynchronizationObject::Signal() { + kernel.Synchronization().SignalObject(*this); +} + void SynchronizationObject::AddWaitingThread(std::shared_ptr thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); if (itr == waiting_threads.end()) diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index a0f891c97..741c31faf 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -30,6 +30,13 @@ public: /// Acquire/lock the object for the specified thread if it is available virtual void Acquire(Thread* thread) = 0; + /// Signal this object + virtual void Signal(); + + virtual bool IsSignaled() const { + return is_signaled; + } + /** * Add a thread to wait on this object * @param thread Pointer to thread to add @@ -60,6 +67,9 @@ public: /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; +protected: + bool is_signaled{}; // Tells if this sync object is signalled; + private: /// Threads waiting for this object to become available std::vector> waiting_threads; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0f096ed6d..ee9ea7d67 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -31,6 +31,10 @@ bool Thread::ShouldWait(const Thread* thread) const { return status != ThreadStatus::Dead; } +bool Thread::IsSignaled() const { + return status == ThreadStatus::Dead; +} + void Thread::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } @@ -45,7 +49,7 @@ void Thread::Stop() { kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); callback_handle = 0; SetStatus(ThreadStatus::Dead); - WakeupAllWaitingThreads(); + Signal(); // Clean up any dangling references in objects that this thread was waiting for for (auto& wait_object : wait_objects) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 895258095..7a4916318 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -146,6 +146,7 @@ public: bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; + bool IsSignaled() const override; /** * Gets the thread's current priority diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp index c9332e3e1..fc2f7c424 100644 --- a/src/core/hle/kernel/writable_event.cpp +++ b/src/core/hle/kernel/writable_event.cpp @@ -22,7 +22,6 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { writable_event->name = name + ":Writable"; writable_event->readable = readable_event; readable_event->name = name + ":Readable"; - readable_event->signaled = false; return {std::move(readable_event), std::move(writable_event)}; } @@ -40,7 +39,7 @@ void WritableEvent::Clear() { } bool WritableEvent::IsSignaled() const { - return readable->signaled; + return readable->IsSignaled(); } } // namespace Kernel -- cgit v1.2.3 From 1e6f8aba04b7be0f90b97aed2527558c755935d6 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 11 Feb 2020 19:56:24 -0400 Subject: Core: Set all hardware emulation constants in a single file. --- src/core/arm/dynarmic/arm_dynarmic.cpp | 3 ++- src/core/core_timing.cpp | 3 ++- src/core/core_timing_util.cpp | 18 +++++++------- src/core/core_timing_util.h | 12 ++++------ src/core/cpu_manager.h | 5 ++-- src/core/hardware_properties.h | 28 ++++++++++++++++++++++ src/core/hle/kernel/scheduler.cpp | 12 +++++----- src/core/hle/kernel/scheduler.h | 13 +++++----- src/core/hle/kernel/thread.cpp | 15 ++++++------ src/core/hle/service/hid/hid.cpp | 7 +++--- src/core/hle/service/nvflinger/nvflinger.cpp | 7 +++--- .../service/time/standard_steady_clock_core.cpp | 3 ++- .../service/time/tick_based_steady_clock_core.cpp | 3 ++- src/core/hle/service/time/time.cpp | 3 ++- src/core/hle/service/time/time_sharedmemory.cpp | 3 ++- src/core/memory/cheat_engine.cpp | 3 ++- src/core/tools/freezer.cpp | 3 ++- 17 files changed, 88 insertions(+), 53 deletions(-) create mode 100644 src/core/hardware_properties.h (limited to 'src/core') diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 791640a3a..29eaf74e5 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -14,6 +14,7 @@ #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/gdbstub/gdbstub.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/svc.h" @@ -153,7 +154,7 @@ std::unique_ptr ARM_Dynarmic::MakeJit(Common::PageTable& pag config.tpidr_el0 = &cb->tpidr_el0; config.dczid_el0 = 4; config.ctr_el0 = 0x8444c004; - config.cntfrq_el0 = Timing::CNTFREQ; + config.cntfrq_el0 = Hardware::CNTFREQ; // Unpredictable instructions config.define_unpredictable_behaviour = true; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index aa09fa453..46d4178c4 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -12,6 +12,7 @@ #include "common/assert.h" #include "common/thread.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" namespace Core::Timing { @@ -215,7 +216,7 @@ void CoreTiming::Idle() { } std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { - return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE}; + return std::chrono::microseconds{GetTicks() * 1000000 / Hardware::BASE_CLOCK_RATE}; } s64 CoreTiming::GetDowncount() const { diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp index a10472a95..de50d3b14 100644 --- a/src/core/core_timing_util.cpp +++ b/src/core/core_timing_util.cpp @@ -11,7 +11,7 @@ namespace Core::Timing { -constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits::max() / BASE_CLOCK_RATE; +constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits::max() / Hardware::BASE_CLOCK_RATE; s64 msToCycles(std::chrono::milliseconds ms) { if (static_cast(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) { @@ -20,9 +20,9 @@ s64 msToCycles(std::chrono::milliseconds ms) { } if (static_cast(ms.count()) > MAX_VALUE_TO_MULTIPLY) { LOG_DEBUG(Core_Timing, "Time very big, do rounding"); - return BASE_CLOCK_RATE * (ms.count() / 1000); + return Hardware::BASE_CLOCK_RATE * (ms.count() / 1000); } - return (BASE_CLOCK_RATE * ms.count()) / 1000; + return (Hardware::BASE_CLOCK_RATE * ms.count()) / 1000; } s64 usToCycles(std::chrono::microseconds us) { @@ -32,9 +32,9 @@ s64 usToCycles(std::chrono::microseconds us) { } if (static_cast(us.count()) > MAX_VALUE_TO_MULTIPLY) { LOG_DEBUG(Core_Timing, "Time very big, do rounding"); - return BASE_CLOCK_RATE * (us.count() / 1000000); + return Hardware::BASE_CLOCK_RATE * (us.count() / 1000000); } - return (BASE_CLOCK_RATE * us.count()) / 1000000; + return (Hardware::BASE_CLOCK_RATE * us.count()) / 1000000; } s64 nsToCycles(std::chrono::nanoseconds ns) { @@ -44,14 +44,14 @@ s64 nsToCycles(std::chrono::nanoseconds ns) { } if (static_cast(ns.count()) > MAX_VALUE_TO_MULTIPLY) { LOG_DEBUG(Core_Timing, "Time very big, do rounding"); - return BASE_CLOCK_RATE * (ns.count() / 1000000000); + return Hardware::BASE_CLOCK_RATE * (ns.count() / 1000000000); } - return (BASE_CLOCK_RATE * ns.count()) / 1000000000; + return (Hardware::BASE_CLOCK_RATE * ns.count()) / 1000000000; } u64 CpuCyclesToClockCycles(u64 ticks) { - const u128 temporal = Common::Multiply64Into128(ticks, CNTFREQ); - return Common::Divide128On32(temporal, static_cast(BASE_CLOCK_RATE)).first; + const u128 temporal = Common::Multiply64Into128(ticks, Hardware::CNTFREQ); + return Common::Divide128On32(temporal, static_cast(Hardware::BASE_CLOCK_RATE)).first; } } // namespace Core::Timing diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h index cdd84d70f..addc72b19 100644 --- a/src/core/core_timing_util.h +++ b/src/core/core_timing_util.h @@ -6,28 +6,24 @@ #include #include "common/common_types.h" +#include "core/hardware_properties.h" namespace Core::Timing { -// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz -// The exact value used is of course unverified. -constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch clock speed is 1020MHz un/docked -constexpr u64 CNTFREQ = 19200000; // Value from fusee. - s64 msToCycles(std::chrono::milliseconds ms); s64 usToCycles(std::chrono::microseconds us); s64 nsToCycles(std::chrono::nanoseconds ns); inline std::chrono::milliseconds CyclesToMs(s64 cycles) { - return std::chrono::milliseconds(cycles * 1000 / BASE_CLOCK_RATE); + return std::chrono::milliseconds(cycles * 1000 / Hardware::BASE_CLOCK_RATE); } inline std::chrono::nanoseconds CyclesToNs(s64 cycles) { - return std::chrono::nanoseconds(cycles * 1000000000 / BASE_CLOCK_RATE); + return std::chrono::nanoseconds(cycles * 1000000000 / Hardware::BASE_CLOCK_RATE); } inline std::chrono::microseconds CyclesToUs(s64 cycles) { - return std::chrono::microseconds(cycles * 1000000 / BASE_CLOCK_RATE); + return std::chrono::microseconds(cycles * 1000000 / Hardware::BASE_CLOCK_RATE); } u64 CpuCyclesToClockCycles(u64 ticks); diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index feb619e1b..97554d1bb 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -6,6 +6,7 @@ #include #include +#include "core/hardware_properties.h" namespace Core { @@ -39,9 +40,7 @@ public: void RunLoop(bool tight_loop); private: - static constexpr std::size_t NUM_CPU_CORES = 4; - - std::array, NUM_CPU_CORES> core_managers; + std::array, Hardware::NUM_CPU_CORES> core_managers; std::size_t active_core{}; ///< Active core, only used in single thread mode System& system; diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h new file mode 100644 index 000000000..62cdf9ef0 --- /dev/null +++ b/src/core/hardware_properties.h @@ -0,0 +1,28 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +namespace Core { + +union EmuThreadHandle { + u64 raw; + struct { + u32 host_handle; + u32 guest_handle; + }; +}; + +namespace Hardware { + +// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz +// The exact value used is of course unverified. +constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked +constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed +constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores +} // namespace Hardware + +} // namespace Core diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index eb196a690..b5ffa5418 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -124,8 +124,8 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { "Thread yielding without being in front"); scheduled_queue[core_id].yield(priority); - std::array current_threads; - for (u32 i = 0; i < NUM_CPU_CORES; i++) { + std::array current_threads; + for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); } @@ -177,8 +177,8 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread // function... if (scheduled_queue[core_id].empty()) { // Here, "current_threads" is calculated after the ""yield"", unlike yield -1 - std::array current_threads; - for (u32 i = 0; i < NUM_CPU_CORES; i++) { + std::array current_threads; + for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); } for (auto& thread : suggested_queue[core_id]) { @@ -208,7 +208,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } void GlobalScheduler::PreemptThreads() { - for (std::size_t core_id = 0; core_id < NUM_CPU_CORES; core_id++) { + for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { const u32 priority = preemption_priorities[core_id]; if (scheduled_queue[core_id].size(priority) > 0) { @@ -349,7 +349,7 @@ bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, } void GlobalScheduler::Shutdown() { - for (std::size_t core = 0; core < NUM_CPU_CORES; core++) { + for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { scheduled_queue[core].clear(); suggested_queue[core].clear(); } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 14b77960a..96db049cb 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "common/multi_level_queue.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/thread.h" namespace Core { @@ -23,8 +24,6 @@ class Process; class GlobalScheduler final { public: - static constexpr u32 NUM_CPU_CORES = 4; - explicit GlobalScheduler(Core::System& system); ~GlobalScheduler(); @@ -125,7 +124,7 @@ public: void PreemptThreads(); u32 CpuCoresCount() const { - return NUM_CPU_CORES; + return Core::Hardware::NUM_CPU_CORES; } void SetReselectionPending() { @@ -149,13 +148,15 @@ private: bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner); static constexpr u32 min_regular_priority = 2; - std::array, NUM_CPU_CORES> scheduled_queue; - std::array, NUM_CPU_CORES> suggested_queue; + std::array, Core::Hardware::NUM_CPU_CORES> + scheduled_queue; + std::array, Core::Hardware::NUM_CPU_CORES> + suggested_queue; std::atomic is_reselection_pending{false}; // The priority levels at which the global scheduler preempts threads every 10 ms. They are // ordered from Core 0 to Core 3. - std::array preemption_priorities = {59, 59, 59, 62}; + std::array preemption_priorities = {59, 59, 59, 62}; /// Lists all thread ids that aren't deleted/etc. std::vector> thread_list; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ee9ea7d67..43b30dd3d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -15,6 +15,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -431,7 +432,7 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { const s32 old_core = processor_id; if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) { if (static_cast(ideal_core) < 0) { - processor_id = HighestSetCore(affinity_mask, GlobalScheduler::NUM_CPU_CORES); + processor_id = HighestSetCore(affinity_mask, Core::Hardware::NUM_CPU_CORES); } else { processor_id = ideal_core; } @@ -455,7 +456,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { scheduler.Unschedule(current_priority, static_cast(processor_id), this); } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Unsuggest(current_priority, core, this); } @@ -466,7 +467,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { scheduler.Schedule(current_priority, static_cast(processor_id), this); } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Suggest(current_priority, core, this); } @@ -485,7 +486,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { scheduler.Unschedule(old_priority, static_cast(processor_id), this); } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Unsuggest(old_priority, core, this); } @@ -502,7 +503,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { } } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Suggest(current_priority, core, this); } @@ -518,7 +519,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { return; } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (((old_affinity_mask >> core) & 1) != 0) { if (core == static_cast(old_core)) { scheduler.Unschedule(current_priority, core, this); @@ -528,7 +529,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { } } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (((affinity_mask >> core) & 1) != 0) { if (core == static_cast(processor_id)) { scheduler.Schedule(current_priority, core, this); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 89bf8b815..e6b56a9f9 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -10,6 +10,7 @@ #include "core/core_timing_util.h" #include "core/frontend/emu_window.h" #include "core/frontend/input.h" +#include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -37,11 +38,11 @@ namespace Service::HID { // Updating period for each HID device. // TODO(ogniK): Find actual polling rate of hid -constexpr s64 pad_update_ticks = static_cast(Core::Timing::BASE_CLOCK_RATE / 66); +constexpr s64 pad_update_ticks = static_cast(Core::Hardware::BASE_CLOCK_RATE / 66); [[maybe_unused]] constexpr s64 accelerometer_update_ticks = - static_cast(Core::Timing::BASE_CLOCK_RATE / 100); + static_cast(Core::Hardware::BASE_CLOCK_RATE / 100); [[maybe_unused]] constexpr s64 gyroscope_update_ticks = - static_cast(Core::Timing::BASE_CLOCK_RATE / 100); + static_cast(Core::Hardware::BASE_CLOCK_RATE / 100); constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system) diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 62752e419..134152210 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -12,6 +12,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" @@ -26,8 +27,8 @@ namespace Service::NVFlinger { -constexpr s64 frame_ticks = static_cast(Core::Timing::BASE_CLOCK_RATE / 60); -constexpr s64 frame_ticks_30fps = static_cast(Core::Timing::BASE_CLOCK_RATE / 30); +constexpr s64 frame_ticks = static_cast(Core::Hardware::BASE_CLOCK_RATE / 60); +constexpr s64 frame_ticks_30fps = static_cast(Core::Hardware::BASE_CLOCK_RATE / 30); NVFlinger::NVFlinger(Core::System& system) : system(system) { displays.emplace_back(0, "Default", system); @@ -222,7 +223,7 @@ void NVFlinger::Compose() { s64 NVFlinger::GetNextTicks() const { constexpr s64 max_hertz = 120LL; - return (Core::Timing::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz; + return (Core::Hardware::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz; } } // namespace Service::NVFlinger diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp index ca1a783fc..1575f0b49 100644 --- a/src/core/hle/service/time/standard_steady_clock_core.cpp +++ b/src/core/hle/service/time/standard_steady_clock_core.cpp @@ -5,6 +5,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/service/time/standard_steady_clock_core.h" namespace Service::Time::Clock { @@ -12,7 +13,7 @@ namespace Service::Time::Clock { TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Timing::CNTFREQ)}; + Core::Hardware::CNTFREQ)}; TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp index c77b98189..44d5bc651 100644 --- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp +++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp @@ -5,6 +5,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/service/time/tick_based_steady_clock_core.h" namespace Service::Time::Clock { @@ -12,7 +13,7 @@ namespace Service::Time::Clock { SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Timing::CNTFREQ)}; + Core::Hardware::CNTFREQ)}; return {ticks_time_span.ToSeconds(), GetClockSourceId()}; } diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 8ef4efcef..749b7be70 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -6,6 +6,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -233,7 +234,7 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { const auto ticks{Clock::TimeSpanType::FromTicks( Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Timing::CNTFREQ)}; + Core::Hardware::CNTFREQ)}; const s64 base_time_point{context.offset + current_time_point.time_point - ticks.ToSeconds()}; IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index 9b03191bf..fdaef233f 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -5,6 +5,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/service/time/clock_types.h" #include "core/hle/service/time/steady_clock_core.h" #include "core/hle/service/time/time_sharedmemory.h" @@ -31,7 +32,7 @@ void SharedMemory::SetupStandardSteadyClock(Core::System& system, Clock::TimeSpanType current_time_point) { const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Timing::CNTFREQ)}; + Core::Hardware::CNTFREQ)}; const Clock::SteadyClockContext context{ static_cast(current_time_point.nanoseconds - ticks_time_span.nanoseconds), clock_source_id}; diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index d1e6bed93..4472500d2 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/process.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" @@ -17,7 +18,7 @@ namespace Memory { -constexpr s64 CHEAT_ENGINE_TICKS = static_cast(Core::Timing::BASE_CLOCK_RATE / 12); +constexpr s64 CHEAT_ENGINE_TICKS = static_cast(Core::Hardware::BASE_CLOCK_RATE / 12); constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 55e0dbc49..1e060f009 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -7,13 +7,14 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/memory.h" #include "core/tools/freezer.h" namespace Tools { namespace { -constexpr s64 MEMORY_FREEZER_TICKS = static_cast(Core::Timing::BASE_CLOCK_RATE / 60); +constexpr s64 MEMORY_FREEZER_TICKS = static_cast(Core::Hardware::BASE_CLOCK_RATE / 60); u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) { switch (width) { -- cgit v1.2.3 From 2bc949628dfa2efe9a18660b9d662e2a25cef9f9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 13 Feb 2020 17:01:44 -0400 Subject: Core: Address Feedback --- src/core/hardware_properties.h | 31 +++++++++++++++++++++++-------- src/core/hle/kernel/scheduler.cpp | 4 ++-- src/core/hle/kernel/server_session.cpp | 2 +- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/kernel/synchronization.cpp | 21 +++++++++++---------- src/core/hle/kernel/synchronization.h | 14 ++++++++++++-- 6 files changed, 50 insertions(+), 24 deletions(-) (limited to 'src/core') diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 62cdf9ef0..947140efb 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h @@ -8,14 +8,6 @@ namespace Core { -union EmuThreadHandle { - u64 raw; - struct { - u32 host_handle; - u32 guest_handle; - }; -}; - namespace Hardware { // The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz @@ -23,6 +15,29 @@ namespace Hardware { constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores + } // namespace Hardware +struct EmuThreadHandle { + u32 host_handle; + u32 guest_handle; + + u64 GetRaw() const { + return (static_cast(host_handle) << 32) | guest_handle; + } + + bool operator==(const EmuThreadHandle& rhs) const { + return std::tie(host_handle, guest_handle) == std::tie(rhs.host_handle, rhs.guest_handle); + } + + bool operator!=(const EmuThreadHandle& rhs) const { + return !operator==(rhs); + } + + static constexpr EmuThreadHandle InvalidHandle() { + constexpr u32 invalid_handle = 0xFFFFFFFF; + return {invalid_handle, invalid_handle}; + } +}; + } // namespace Core diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index b5ffa5418..86f1421bf 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -125,7 +125,7 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { scheduled_queue[core_id].yield(priority); std::array current_threads; - for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + for (std::size_t i = 0; i < current_threads.size(); i++) { current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); } @@ -178,7 +178,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread if (scheduled_queue[core_id].empty()) { // Here, "current_threads" is calculated after the ""yield"", unlike yield -1 std::array current_threads; - for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + for (std::size_t i = 0; i < current_threads.size(); i++) { current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); } for (auto& thread : suggested_queue[core_id]) { diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index ca98fd984..4604e35c5 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -57,7 +57,7 @@ bool ServerSession::IsSignaled() const { } // Wait if we have no pending requests, or if we're currently handling a request. - return !(pending_requesting_threads.empty() || currently_handling != nullptr); + return !pending_requesting_threads.empty() && currently_handling == nullptr; } void ServerSession::Acquire(Thread* thread) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 86c660cdf..fd91779a3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -474,7 +474,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr objects[i] = object; } auto& synchronization = kernel.Synchronization(); - auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds); + const auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds); *index = handle_result; return result; } diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 25afc162f..dc37fad1a 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -4,6 +4,7 @@ #include "core/core.h" #include "core/hle/kernel/errors.h" +#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/synchronization.h" @@ -27,30 +28,30 @@ static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_p thread->SetWaitSynchronizationResult(RESULT_SUCCESS); thread->SetWaitSynchronizationOutput(static_cast(index)); return true; -}; +} Synchronization::Synchronization(Core::System& system) : system{system} {} void Synchronization::SignalObject(SynchronizationObject& obj) const { if (obj.IsSignaled()) { obj.WakeupAllWaitingThreads(); - }; + } } std::pair Synchronization::WaitFor( std::vector>& sync_objects, s64 nano_seconds) { auto* const thread = system.CurrentScheduler().GetCurrentThread(); // Find the first object that is acquirable in the provided list of objects - auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), - [thread](const std::shared_ptr& object) { - return object->IsSignaled(); - }); + const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), + [thread](const std::shared_ptr& object) { + return object->IsSignaled(); + }); if (itr != sync_objects.end()) { // We found a ready object, acquire it and set the result value SynchronizationObject* object = itr->get(); object->Acquire(thread); - u32 index = static_cast(std::distance(sync_objects.begin(), itr)); + const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); return {RESULT_SUCCESS, index}; } @@ -59,12 +60,12 @@ std::pair Synchronization::WaitFor( // If a timeout value of 0 was provided, just return the Timeout error code instead of // suspending the thread. if (nano_seconds == 0) { - return {RESULT_TIMEOUT, 0}; + return {RESULT_TIMEOUT, InvalidHandle}; } if (thread->IsSyncCancelled()) { thread->SetSyncCancelled(false); - return {ERR_SYNCHRONIZATION_CANCELED, 0}; + return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; } for (auto& object : sync_objects) { @@ -80,7 +81,7 @@ std::pair Synchronization::WaitFor( system.PrepareReschedule(thread->GetProcessorID()); - return {RESULT_TIMEOUT, 0}; + return {RESULT_TIMEOUT, InvalidHandle}; } } // namespace Kernel diff --git a/src/core/hle/kernel/synchronization.h b/src/core/hle/kernel/synchronization.h index 3417a9f13..379f4b1d3 100644 --- a/src/core/hle/kernel/synchronization.h +++ b/src/core/hle/kernel/synchronization.h @@ -6,6 +6,7 @@ #include #include +#include #include "core/hle/kernel/object.h" #include "core/hle/result.h" @@ -16,15 +17,24 @@ class System; namespace Kernel { -class KernelCore; class SynchronizationObject; +/** + * The 'Synchronization' class is an interface for handling synchronization methods + * used by Synchronization objects and synchronization SVCs. This centralizes processing of + * such + */ class Synchronization { public: - Synchronization(Core::System& system); + explicit Synchronization(Core::System& system); + /// Signals a synchronization object, waking up all its waiting threads void SignalObject(SynchronizationObject& obj) const; + /// Tries to see if waiting for any of the sync_objects is necessary, if not + /// it returns Success and the handle index of the signaled sync object. In + /// case not, the current thread will be locked and wait for nano_seconds or + /// for a synchronization object to signal. std::pair WaitFor( std::vector>& sync_objects, s64 nano_seconds); -- cgit v1.2.3 From 829d8c0d6bbe877862505eebf52b86b4ea9cb83d Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 13 Feb 2020 22:08:49 -0400 Subject: Core: Correct compilition in GCC --- src/core/hardware_properties.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/core') diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 947140efb..213461b6a 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "common/common_types.h" namespace Core { -- cgit v1.2.3