From cef5f45de2fd64f0728d4504d0ad7434cb8ac519 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Wed, 4 Jan 2017 10:44:38 -0500
Subject: [PATCH] Kernel: Use different thread statuses when a thread calls
 WaitSynchronization1 and  WaitSynchronizationN with wait_all = true.

This commit removes the overly general THREADSTATUS_WAIT_SYNCH and replaces it with two more granular statuses:

THREADSTATUS_WAIT_SYNCH_ANY when a thread waits on objects via WaitSynchronization1 or WaitSynchronizationN with wait_all = false.

THREADSTATUS_WAIT_SYNCH_ALL when a thread waits on objects via WaitSynchronizationN with wait_all = true.
---
 src/citra_qt/debugger/wait_tree.cpp |  9 ++++++---
 src/core/hle/kernel/thread.cpp      | 11 +++++++----
 src/core/hle/kernel/thread.h        | 19 ++++++++++---------
 src/core/hle/svc.cpp                |  6 +++---
 4 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp
index 1d2de5185f..b6ecf38194 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/citra_qt/debugger/wait_tree.cpp
@@ -153,7 +153,8 @@ QString WaitTreeThread::GetText() const {
     case THREADSTATUS_WAIT_SLEEP:
         status = tr("sleeping");
         break;
-    case THREADSTATUS_WAIT_SYNCH:
+    case THREADSTATUS_WAIT_SYNCH_ALL:
+    case THREADSTATUS_WAIT_SYNCH_ANY:
         status = tr("waiting for objects");
         break;
     case THREADSTATUS_DORMANT:
@@ -180,7 +181,8 @@ QColor WaitTreeThread::GetColor() const {
         return QColor(Qt::GlobalColor::darkRed);
     case THREADSTATUS_WAIT_SLEEP:
         return QColor(Qt::GlobalColor::darkYellow);
-    case THREADSTATUS_WAIT_SYNCH:
+    case THREADSTATUS_WAIT_SYNCH_ALL:
+    case THREADSTATUS_WAIT_SYNCH_ANY:
         return QColor(Qt::GlobalColor::red);
     case THREADSTATUS_DORMANT:
         return QColor(Qt::GlobalColor::darkCyan);
@@ -228,7 +230,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
     } else {
         list.push_back(std::make_unique<WaitTreeMutexList>(thread.held_mutexes));
     }
-    if (thread.status == THREADSTATUS_WAIT_SYNCH) {
+    if (thread.status == THREADSTATUS_WAIT_SYNCH_ANY ||
+        thread.status == THREADSTATUS_WAIT_SYNCH_ALL) {
         list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects,
                                                             thread.IsSleepingOnWaitAll()));
     }
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 3a5a67450d..aa99d18c71 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -72,7 +72,8 @@ Thread* GetCurrentThread() {
  * @return True if the thread is waiting, false otherwise
  */
 static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) {
-    if (thread->status != THREADSTATUS_WAIT_SYNCH)
+    if (thread->status != THREADSTATUS_WAIT_SYNCH_ALL &&
+        thread->status != THREADSTATUS_WAIT_SYNCH_ANY)
         return false;
 
     auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object);
@@ -253,7 +254,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
     Thread* thread = GetCurrentThread();
     thread->wait_set_output = wait_set_output;
     thread->wait_objects = std::move(wait_objects);
-    thread->status = THREADSTATUS_WAIT_SYNCH;
+    thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
 }
 
 void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
@@ -281,7 +282,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
         return;
     }
 
-    if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) {
+    if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
+        thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) {
         thread->wait_set_output = false;
         // Remove the thread from each of its waiting objects' waitlists
         for (auto& object : thread->wait_objects)
@@ -306,7 +308,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
 
 void Thread::ResumeFromWait() {
     switch (status) {
-    case THREADSTATUS_WAIT_SYNCH:
+    case THREADSTATUS_WAIT_SYNCH_ALL:
+    case THREADSTATUS_WAIT_SYNCH_ANY:
     case THREADSTATUS_WAIT_ARB:
     case THREADSTATUS_WAIT_SLEEP:
         break;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index e2f0cc831f..6cd8c20e27 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -31,13 +31,14 @@ enum ThreadProcessorId : s32 {
 };
 
 enum ThreadStatus {
-    THREADSTATUS_RUNNING,    ///< Currently running
-    THREADSTATUS_READY,      ///< Ready to run
-    THREADSTATUS_WAIT_ARB,   ///< Waiting on an address arbiter
-    THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
-    THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC
-    THREADSTATUS_DORMANT,    ///< Created but not yet made ready
-    THREADSTATUS_DEAD        ///< Run to completion, or forcefully terminated
+    THREADSTATUS_RUNNING,        ///< Currently running
+    THREADSTATUS_READY,          ///< Ready to run
+    THREADSTATUS_WAIT_ARB,       ///< Waiting on an address arbiter
+    THREADSTATUS_WAIT_SLEEP,     ///< Waiting due to a SleepThread SVC
+    THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
+    THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
+    THREADSTATUS_DORMANT,        ///< Created but not yet made ready
+    THREADSTATUS_DEAD            ///< Run to completion, or forcefully terminated
 };
 
 namespace Kernel {
@@ -158,10 +159,10 @@ public:
     /**
      * 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, or a ReplyAndReceive call.
+     * with wait_all = true.
      */
     bool IsSleepingOnWaitAll() const {
-        return !wait_objects.empty();
+        return status == THREADSTATUS_WAIT_SYNCH_ALL;
     }
 
     ARM_Interface::ThreadContext context;
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 160f27c98a..1e1ca5180c 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -278,7 +278,7 @@ static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds)
             return ERR_SYNC_TIMEOUT;
 
         object->AddWaitingThread(thread);
-        thread->status = THREADSTATUS_WAIT_SYNCH;
+        thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
 
         // Create an event to wake the thread up after the specified nanosecond delay has passed
         thread->WakeAfterDelay(nano_seconds);
@@ -351,7 +351,7 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha
             return ERR_SYNC_TIMEOUT;
 
         // Put the thread to sleep
-        thread->status = THREADSTATUS_WAIT_SYNCH;
+        thread->status = THREADSTATUS_WAIT_SYNCH_ALL;
 
         // Add the thread to each of the objects' waiting threads.
         for (auto& object : objects) {
@@ -393,7 +393,7 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha
             return ERR_SYNC_TIMEOUT;
 
         // Put the thread to sleep
-        thread->status = THREADSTATUS_WAIT_SYNCH;
+        thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
 
         // Clear the thread's waitlist, we won't use it for wait_all = false
         thread->wait_objects.clear();