From 433b59c1121a257ae3c1503fff5b71d3f3852ab5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Apr 2019 07:08:12 -0400 Subject: kernel/svc: Migrate svcCancelSynchronization behavior to a thread function The actual behavior of this function is slightly more complex than what we're currently doing within the supervisor call. To avoid dumping most of this behavior in the supervisor call itself, we can migrate this to another function. --- src/core/hle/kernel/svc.cpp | 6 ++---- src/core/hle/kernel/thread.cpp | 6 ++++++ src/core/hle/kernel/thread.h | 12 +++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d48a2203a..b25190882 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -518,16 +518,14 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr thread = handle_table.Get(thread_handle); + SharedPtr thread = handle_table.Get(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); return ERR_INVALID_HANDLE; } - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); - thread->SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); - thread->ResumeFromWait(); + thread->CancelWait(); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ca52267b2..7d4fe9608 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -142,6 +142,12 @@ void Thread::ResumeFromWait() { ChangeScheduler(); } +void Thread::CancelWait() { + ASSERT(GetStatus() == ThreadStatus::WaitSynchAny); + SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); + ResumeFromWait(); +} + /** * Resets a thread context, making it ready to be scheduled and run by the CPU * @param context Thread context to reset diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 32026d7f0..e3c457408 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -164,11 +164,17 @@ public: return tls_memory; } - /** - * Resumes a thread from waiting - */ + /// Resumes a thread from waiting void ResumeFromWait(); + /// Cancels a waiting operation that this thread may or may not be within. + /// + /// When the thread is within a waiting state, this will set the thread's + /// waiting result to signal a canceled wait. The function will then resume + /// this thread. + /// + void CancelWait(); + /** * Schedules an event to wake up the specified thread after the specified delay * @param nanoseconds The time this thread will be allowed to sleep for -- cgit v1.2.3 From c268ffd831bc8771585934e7e24da0f7e150936e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 17 Apr 2019 07:21:19 -0400 Subject: kernel/thread: Unify wait synchronization types This is a holdover from Citra, where the 3DS has both WaitSynchronization1 and WaitSynchronizationN. The switch only has one form of wait synchronizing (literally WaitSynchonization). This allows us to throw out code that doesn't apply at all to the Switch kernel. Because of this unnecessary dichotomy within the wait synchronization utilities, we were also neglecting to properly handle waiting on multiple objects. While we're at it, we can also scrub out any lingering references to WaitSynchronization1/WaitSynchronizationN in comments, and change them to WaitSynchronization (or remove them if the mention no longer applies). --- src/core/hle/kernel/kernel.cpp | 3 +-- src/core/hle/kernel/process.cpp | 3 +-- src/core/hle/kernel/svc.cpp | 4 ++-- src/core/hle/kernel/thread.cpp | 5 ++--- src/core/hle/kernel/thread.h | 28 +++++++++++++--------------- src/core/hle/kernel/wait_object.cpp | 29 +++++++++++++++-------------- 6 files changed, 34 insertions(+), 38 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 4d58e7c69..a38ee117b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -46,8 +46,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ bool resume = true; - if (thread->GetStatus() == ThreadStatus::WaitSynchAny || - thread->GetStatus() == ThreadStatus::WaitSynchAll || + 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()) { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 4e94048da..0ace3d21c 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -150,8 +150,7 @@ void Process::PrepareForTermination() { continue; // TODO(Subv): When are the other running/ready threads terminated? - ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynchAny || - thread->GetStatus() == ThreadStatus::WaitSynchAll, + ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynch, "Exiting processes with non-waiting threads is currently unimplemented"); thread->Stop(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b25190882..ea3fdc315 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -424,7 +424,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han /// Default thread wakeup callback for WaitSynchronization static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr thread, SharedPtr object, std::size_t index) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); if (reason == ThreadWakeupReason::Timeout) { thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); @@ -502,7 +502,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr } thread->SetWaitObjects(std::move(objects)); - thread->SetStatus(ThreadStatus::WaitSynchAny); + thread->SetStatus(ThreadStatus::WaitSynch); // Create an event to wake the thread up after the specified nanosecond delay has passed thread->WakeAfterDelay(nano_seconds); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 7d4fe9608..2abf9efca 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -101,8 +101,7 @@ void Thread::ResumeFromWait() { ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); switch (status) { - case ThreadStatus::WaitSynchAll: - case ThreadStatus::WaitSynchAny: + case ThreadStatus::WaitSynch: case ThreadStatus::WaitHLEEvent: case ThreadStatus::WaitSleep: case ThreadStatus::WaitIPC: @@ -143,7 +142,7 @@ void Thread::ResumeFromWait() { } void Thread::CancelWait() { - ASSERT(GetStatus() == ThreadStatus::WaitSynchAny); + ASSERT(GetStatus() == ThreadStatus::WaitSynch); SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); ResumeFromWait(); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index e3c457408..62ce7bfda 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -49,8 +49,7 @@ enum class ThreadStatus { WaitHLEEvent, ///< Waiting for hle event to finish WaitSleep, ///< Waiting due to a SleepThread SVC WaitIPC, ///< Waiting for the reply from an IPC request - WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false - WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true + WaitSynch, ///< Waiting due to WaitSynchronization WaitMutex, ///< Waiting due to an ArbitrateLock svc WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc @@ -185,24 +184,27 @@ public: void CancelWakeupTimer(); /** - * Sets the result after the thread awakens (from either WaitSynchronization SVC) + * Sets the result after the thread awakens (from svcWaitSynchronization) * @param result Value to set to the returned result */ void SetWaitSynchronizationResult(ResultCode result); /** - * Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only) + * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) * @param output Value to set to the output parameter */ void SetWaitSynchronizationOutput(s32 output); /** * Retrieves the index that this particular object occupies in the list of objects - * that the thread passed to WaitSynchronizationN, starting the search from the last element. - * It is used to set the output value of WaitSynchronizationN when the thread is awakened. + * that the thread passed to WaitSynchronization, starting the search from the last element. + * + * It is used to set the output index of WaitSynchronization when the thread is awakened. + * * When a thread wakes up due to an object signal, the kernel will use the index of the last * matching object in the wait objects list in case of having multiple instances of the same * object in the list. + * * @param object Object to query the index of. */ s32 GetWaitObjectIndex(const WaitObject* object) const; @@ -239,13 +241,9 @@ public: */ VAddr GetCommandBufferAddress() const; - /** - * Returns whether this thread is waiting for all the objects in - * its wait list to become ready, as a result of a WaitSynchronizationN call - * with wait_all = true. - */ - bool IsSleepingOnWaitAll() const { - return status == ThreadStatus::WaitSynchAll; + /// Returns whether this thread is waiting on objects from a WaitSynchronization call. + bool IsSleepingOnWait() const { + return status == ThreadStatus::WaitSynch; } ThreadContext& GetContext() { @@ -423,7 +421,7 @@ private: Process* owner_process; /// Objects that the thread is waiting on, in the same order as they were - /// passed to WaitSynchronization1/N. + /// passed to WaitSynchronization. ThreadWaitObjects wait_objects; /// List of threads that are waiting for a mutex that is held by this thread. @@ -449,7 +447,7 @@ private: Handle callback_handle = 0; /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread - /// was waiting via WaitSynchronizationN then the object will be the last object that became + /// was waiting via WaitSynchronization then the object will be the last object that became /// available. In case of a timeout, the object will be nullptr. WakeupCallback wakeup_callback; diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 90580ed93..38d8a6e0c 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -38,8 +38,7 @@ SharedPtr WaitObject::GetHighestPriorityReadyThread() { 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::WaitSynchAny || - thread_status == ThreadStatus::WaitSynchAll || + ASSERT_MSG(thread_status == ThreadStatus::WaitSynch || thread_status == ThreadStatus::WaitHLEEvent, "Inconsistent thread statuses in waiting_threads"); @@ -49,10 +48,10 @@ SharedPtr WaitObject::GetHighestPriorityReadyThread() { if (ShouldWait(thread.get())) continue; - // A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or - // in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready. + // A thread is ready to run if it's either in ThreadStatus::WaitSynch + // and the rest of the objects it is waiting on are ready. bool ready_to_run = true; - if (thread_status == ThreadStatus::WaitSynchAll) { + if (thread_status == ThreadStatus::WaitSynch) { ready_to_run = thread->AllWaitObjectsReady(); } @@ -68,33 +67,35 @@ SharedPtr WaitObject::GetHighestPriorityReadyThread() { void WaitObject::WakeupWaitingThread(SharedPtr thread) { ASSERT(!ShouldWait(thread.get())); - if (!thread) + if (!thread) { return; + } - if (!thread->IsSleepingOnWaitAll()) { - Acquire(thread.get()); - } else { + 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(this); - for (const auto& object : thread->GetWaitObjects()) + for (const auto& object : thread->GetWaitObjects()) { object->RemoveWaitingThread(thread.get()); + } thread->ClearWaitObjects(); thread->CancelWakeupTimer(); bool resume = true; - - if (thread->HasWakeupCallback()) + if (thread->HasWakeupCallback()) { resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index); - - if (resume) + } + if (resume) { thread->ResumeFromWait(); + } } void WaitObject::WakeupAllWaitingThreads() { -- cgit v1.2.3