summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/event.h1
-rw-r--r--src/core/hle/kernel/kernel.cpp79
-rw-r--r--src/core/hle/kernel/kernel.h53
-rw-r--r--src/core/hle/kernel/mutex.h1
-rw-r--r--src/core/hle/kernel/semaphore.h1
-rw-r--r--src/core/hle/kernel/server_port.h1
-rw-r--r--src/core/hle/kernel/server_session.h1
-rw-r--r--src/core/hle/kernel/thread.h1
-rw-r--r--src/core/hle/kernel/timer.h1
-rw-r--r--src/core/hle/kernel/wait_object.cpp99
-rw-r--r--src/core/hle/kernel/wait_object.h67
-rw-r--r--src/core/hle/svc.cpp1
13 files changed, 176 insertions, 132 deletions
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"