Переглянути джерело

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.
Yuri Kunde Schlesner 9 роки тому
батько
коміт
64ecf81a3c

+ 1 - 0
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() {}
 

+ 1 - 3
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"
 

+ 2 - 0
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

+ 1 - 0
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 {
 

+ 0 - 79
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();

+ 0 - 53
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

+ 1 - 0
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 {
 

+ 1 - 0
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 {
 

+ 1 - 0
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;

+ 1 - 0
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"

+ 1 - 0
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 {

+ 1 - 0
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 {
 

+ 99 - 0
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

+ 67 - 0
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

+ 1 - 0
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"