Merge pull request #2416 from lioncash/wait
kernel/svc: Clean up wait synchronization related functionality
This commit is contained in:
		
						commit
						78574e7a47
					
				| @ -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()) { | ||||
|  | ||||
| @ -147,8 +147,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(); | ||||
|  | ||||
| @ -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> thread, | ||||
|                                         SharedPtr<WaitObject> 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); | ||||
| @ -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> thread = handle_table.Get<Thread>(thread_handle); | ||||
|     SharedPtr<Thread> thread = handle_table.Get<Thread>(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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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: | ||||
| @ -142,6 +141,12 @@ void Thread::ResumeFromWait() { | ||||
|     ChangeScheduler(); | ||||
| } | ||||
| 
 | ||||
| void Thread::CancelWait() { | ||||
|     ASSERT(GetStatus() == ThreadStatus::WaitSynch); | ||||
|     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 | ||||
|  | ||||
| @ -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
 | ||||
| @ -169,11 +168,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 | ||||
| @ -184,24 +189,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; | ||||
| @ -238,13 +246,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() { | ||||
| @ -418,7 +422,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.
 | ||||
| @ -441,7 +445,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; | ||||
| 
 | ||||
|  | ||||
| @ -38,8 +38,7 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { | ||||
|         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<Thread> WaitObject::GetHighestPriorityReadyThread() const { | ||||
|         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<Thread> WaitObject::GetHighestPriorityReadyThread() const { | ||||
| void WaitObject::WakeupWaitingThread(SharedPtr<Thread> 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() { | ||||
|  | ||||
| @ -227,8 +227,7 @@ QString WaitTreeThread::GetText() const { | ||||
|     case Kernel::ThreadStatus::WaitIPC: | ||||
|         status = tr("waiting for IPC reply"); | ||||
|         break; | ||||
|     case Kernel::ThreadStatus::WaitSynchAll: | ||||
|     case Kernel::ThreadStatus::WaitSynchAny: | ||||
|     case Kernel::ThreadStatus::WaitSynch: | ||||
|         status = tr("waiting for objects"); | ||||
|         break; | ||||
|     case Kernel::ThreadStatus::WaitMutex: | ||||
| @ -269,8 +268,7 @@ QColor WaitTreeThread::GetColor() const { | ||||
|         return QColor(Qt::GlobalColor::darkRed); | ||||
|     case Kernel::ThreadStatus::WaitSleep: | ||||
|         return QColor(Qt::GlobalColor::darkYellow); | ||||
|     case Kernel::ThreadStatus::WaitSynchAll: | ||||
|     case Kernel::ThreadStatus::WaitSynchAny: | ||||
|     case Kernel::ThreadStatus::WaitSynch: | ||||
|     case Kernel::ThreadStatus::WaitMutex: | ||||
|     case Kernel::ThreadStatus::WaitCondVar: | ||||
|     case Kernel::ThreadStatus::WaitArb: | ||||
| @ -325,10 +323,9 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | ||||
|         list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); | ||||
|     } | ||||
| 
 | ||||
|     if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAny || | ||||
|         thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAll) { | ||||
|     if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { | ||||
|         list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(), | ||||
|                                                             thread.IsSleepingOnWaitAll())); | ||||
|                                                             thread.IsSleepingOnWait())); | ||||
|     } | ||||
| 
 | ||||
|     list.push_back(std::make_unique<WaitTreeCallstack>(thread)); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei