From 64ecf81a3cf6d6e0a4e4e915e1da2f0bcf2f1cb4 Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Mon, 29 May 2017 15:45:30 -0700
Subject: [PATCH] Kernel: Move WaitObject to a separate file

Now that HandleTable doesn't directly depend on WaitObject anymore, this
can be separated from the main kernel.h header.
---
 src/citra_qt/debugger/wait_tree.cpp  |  1 +
 src/citra_qt/debugger/wait_tree.h    |  4 +-
 src/core/CMakeLists.txt              |  2 +
 src/core/hle/kernel/event.h          |  1 +
 src/core/hle/kernel/kernel.cpp       | 79 ----------------------
 src/core/hle/kernel/kernel.h         | 53 ---------------
 src/core/hle/kernel/mutex.h          |  1 +
 src/core/hle/kernel/semaphore.h      |  1 +
 src/core/hle/kernel/server_port.h    |  1 +
 src/core/hle/kernel/server_session.h |  1 +
 src/core/hle/kernel/thread.h         |  1 +
 src/core/hle/kernel/timer.h          |  1 +
 src/core/hle/kernel/wait_object.cpp  | 99 ++++++++++++++++++++++++++++
 src/core/hle/kernel/wait_object.h    | 67 +++++++++++++++++++
 src/core/hle/svc.cpp                 |  1 +
 15 files changed, 178 insertions(+), 135 deletions(-)
 create mode 100644 src/core/hle/kernel/wait_object.cpp
 create mode 100644 src/core/hle/kernel/wait_object.h

diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp
index b6ecf3819..8c244b6b2 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/citra_qt/debugger/wait_tree.cpp
@@ -10,6 +10,7 @@
 #include "core/hle/kernel/semaphore.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/timer.h"
+#include "core/hle/kernel/wait_object.h"
 
 WaitTreeItem::~WaitTreeItem() {}
 
diff --git a/src/citra_qt/debugger/wait_tree.h b/src/citra_qt/debugger/wait_tree.h
index ee9708fc1..06ef58ea7 100644
--- a/src/citra_qt/debugger/wait_tree.h
+++ b/src/citra_qt/debugger/wait_tree.h
@@ -4,12 +4,10 @@
 
 #pragma once
 
-#include <boost/container/flat_set.hpp>
-
 #include <QAbstractItemModel>
 #include <QDockWidget>
 #include <QTreeView>
-
+#include <boost/container/flat_set.hpp>
 #include "core/core.h"
 #include "core/hle/kernel/kernel.h"
 
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7aa81e885..ba24a6e02 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRCS
             hle/kernel/thread.cpp
             hle/kernel/timer.cpp
             hle/kernel/vm_manager.cpp
+            hle/kernel/wait_object.cpp
             hle/service/ac/ac.cpp
             hle/service/ac/ac_i.cpp
             hle/service/ac/ac_u.cpp
@@ -249,6 +250,7 @@ set(HEADERS
             hle/kernel/thread.h
             hle/kernel/timer.h
             hle/kernel/vm_manager.h
+            hle/kernel/wait_object.h
             hle/result.h
             hle/service/ac/ac.h
             hle/service/ac/ac_i.h
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 3e3673508..cc41abb85 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -6,6 +6,7 @@
 
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/wait_object.h"
 
 namespace Kernel {
 
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 7f84e01aa..b0af5b9b8 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -20,85 +20,6 @@ namespace Kernel {
 unsigned int Object::next_object_id;
 HandleTable g_handle_table;
 
-void WaitObject::AddWaitingThread(SharedPtr<Thread> 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(Thread* 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);
-}
-
-SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
-    Thread* candidate = nullptr;
-    s32 candidate_priority = THREADPRIO_LOWEST + 1;
-
-    for (const auto& thread : waiting_threads) {
-        // The list of waiting threads must not contain threads that are not waiting to be awakened.
-        ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
-                       thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
-                   "Inconsistent thread statuses in waiting_threads");
-
-        if (thread->current_priority >= candidate_priority)
-            continue;
-
-        if (ShouldWait(thread.get()))
-            continue;
-
-        // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
-        // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
-        bool ready_to_run = true;
-        if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
-            ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
-                                        [&thread](const SharedPtr<WaitObject>& object) {
-                                            return object->ShouldWait(thread.get());
-                                        });
-        }
-
-        if (ready_to_run) {
-            candidate = thread.get();
-            candidate_priority = thread->current_priority;
-        }
-    }
-
-    return candidate;
-}
-
-void WaitObject::WakeupAllWaitingThreads() {
-    while (auto thread = GetHighestPriorityReadyThread()) {
-        if (!thread->IsSleepingOnWaitAll()) {
-            Acquire(thread.get());
-            // Set the output index of the WaitSynchronizationN call to the index of this object.
-            if (thread->wait_set_output) {
-                thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
-                thread->wait_set_output = false;
-            }
-        } else {
-            for (auto& object : thread->wait_objects) {
-                object->Acquire(thread.get());
-            }
-            // Note: This case doesn't update the output index of WaitSynchronizationN.
-        }
-
-        for (auto& object : thread->wait_objects)
-            object->RemoveWaitingThread(thread.get());
-        thread->wait_objects.clear();
-
-        thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
-        thread->ResumeFromWait();
-    }
-}
-
-const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
-    return waiting_threads;
-}
-
 HandleTable::HandleTable() {
     next_generation = 1;
     Clear();
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 4344264dc..5335a961d 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -17,8 +17,6 @@ namespace Kernel {
 
 using Handle = u32;
 
-class Thread;
-
 enum KernelHandle : Handle {
     CurrentThread = 0xFFFF8000,
     CurrentProcess = 0xFFFF8001,
@@ -133,57 +131,6 @@ inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
     return nullptr;
 }
 
-/// Class that represents a Kernel object that a thread can be waiting on
-class WaitObject : public Object {
-public:
-    /**
-     * 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(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
-     */
-    virtual void AddWaitingThread(SharedPtr<Thread> thread);
-
-    /**
-     * Removes a thread from waiting on this object (e.g. if it was resumed already)
-     * @param thread Pointer to thread to remove
-     */
-    virtual void RemoveWaitingThread(Thread* 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.
-     */
-    virtual void WakeupAllWaitingThreads();
-
-    /// Obtains the highest priority thread that is ready to run from this object's waiting list.
-    SharedPtr<Thread> GetHighestPriorityReadyThread();
-
-    /// Get a const reference to the waiting threads list for debug use
-    const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
-
-private:
-    /// Threads waiting for this object to become available
-    std::vector<SharedPtr<Thread>> waiting_threads;
-};
-
-// Specialization of DynamicObjectCast for WaitObjects
-template <>
-inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) {
-    if (object != nullptr && object->IsWaitable()) {
-        return boost::static_pointer_cast<WaitObject>(std::move(object));
-    }
-    return nullptr;
-}
-
 /**
  * This class allows the creation of Handles, which are references to objects that can be tested
  * for validity and looked up. Here they are used to pass references to kernel objects to/from the
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index c57adf400..bacacd690 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -7,6 +7,7 @@
 #include <string>
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/wait_object.h"
 
 namespace Kernel {
 
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index cde94f7cc..ca6f908aa 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -8,6 +8,7 @@
 #include <string>
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/wait_object.h"
 
 namespace Kernel {
 
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 6f8bdb6a9..2a24d8412 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -9,6 +9,7 @@
 #include <tuple>
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/wait_object.h"
 
 namespace Service {
 class SessionRequestHandler;
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index c907d487c..315b80d14 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -11,6 +11,7 @@
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/session.h"
 #include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/wait_object.h"
 #include "core/hle/result.h"
 #include "core/hle/service/service.h"
 #include "core/memory.h"
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 7b5169cfc..6a3566f15 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -12,6 +12,7 @@
 #include "common/common_types.h"
 #include "core/arm/arm_interface.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/wait_object.h"
 #include "core/hle/result.h"
 
 enum ThreadPriority : s32 {
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index b0f818933..82552372d 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -6,6 +6,7 @@
 
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/wait_object.h"
 
 namespace Kernel {
 
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
new file mode 100644
index 000000000..f245eda6c
--- /dev/null
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -0,0 +1,99 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/hle/config_mem.h"
+#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/memory.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/timer.h"
+#include "core/hle/shared_page.h"
+
+namespace Kernel {
+
+void WaitObject::AddWaitingThread(SharedPtr<Thread> 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(Thread* 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);
+}
+
+SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
+    Thread* candidate = nullptr;
+    s32 candidate_priority = THREADPRIO_LOWEST + 1;
+
+    for (const auto& thread : waiting_threads) {
+        // The list of waiting threads must not contain threads that are not waiting to be awakened.
+        ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
+                       thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
+                   "Inconsistent thread statuses in waiting_threads");
+
+        if (thread->current_priority >= candidate_priority)
+            continue;
+
+        if (ShouldWait(thread.get()))
+            continue;
+
+        // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
+        // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
+        bool ready_to_run = true;
+        if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
+            ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
+                                        [&thread](const SharedPtr<WaitObject>& object) {
+                                            return object->ShouldWait(thread.get());
+                                        });
+        }
+
+        if (ready_to_run) {
+            candidate = thread.get();
+            candidate_priority = thread->current_priority;
+        }
+    }
+
+    return candidate;
+}
+
+void WaitObject::WakeupAllWaitingThreads() {
+    while (auto thread = GetHighestPriorityReadyThread()) {
+        if (!thread->IsSleepingOnWaitAll()) {
+            Acquire(thread.get());
+            // Set the output index of the WaitSynchronizationN call to the index of this object.
+            if (thread->wait_set_output) {
+                thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
+                thread->wait_set_output = false;
+            }
+        } else {
+            for (auto& object : thread->wait_objects) {
+                object->Acquire(thread.get());
+            }
+            // Note: This case doesn't update the output index of WaitSynchronizationN.
+        }
+
+        for (auto& object : thread->wait_objects)
+            object->RemoveWaitingThread(thread.get());
+        thread->wait_objects.clear();
+
+        thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
+        thread->ResumeFromWait();
+    }
+}
+
+const std::vector<SharedPtr<Thread>>& 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
new file mode 100644
index 000000000..861578186
--- /dev/null
+++ b/src/core/hle/kernel/wait_object.h
@@ -0,0 +1,67 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+#include "common/common_types.h"
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+class Thread;
+
+/// Class that represents a Kernel object that a thread can be waiting on
+class WaitObject : public Object {
+public:
+    /**
+     * 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(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
+     */
+    virtual void AddWaitingThread(SharedPtr<Thread> thread);
+
+    /**
+     * Removes a thread from waiting on this object (e.g. if it was resumed already)
+     * @param thread Pointer to thread to remove
+     */
+    virtual void RemoveWaitingThread(Thread* 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.
+     */
+    virtual void WakeupAllWaitingThreads();
+
+    /// Obtains the highest priority thread that is ready to run from this object's waiting list.
+    SharedPtr<Thread> GetHighestPriorityReadyThread();
+
+    /// Get a const reference to the waiting threads list for debug use
+    const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
+
+private:
+    /// Threads waiting for this object to become available
+    std::vector<SharedPtr<Thread>> waiting_threads;
+};
+
+// Specialization of DynamicObjectCast for WaitObjects
+template <>
+inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) {
+    if (object != nullptr && object->IsWaitable()) {
+        return boost::static_pointer_cast<WaitObject>(std::move(object));
+    }
+    return nullptr;
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 243c54c6e..83767677f 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -27,6 +27,7 @@
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/timer.h"
 #include "core/hle/kernel/vm_manager.h"
+#include "core/hle/kernel/wait_object.h"
 #include "core/hle/result.h"
 #include "core/hle/service/service.h"