summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/kernel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
-rw-r--r--src/core/hle/kernel/kernel.cpp49
1 files changed, 27 insertions, 22 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1db8e102f..f599916f0 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <boost/range/algorithm_ext/erase.hpp>
7#include "common/assert.h" 6#include "common/assert.h"
8#include "common/logging/log.h" 7#include "common/logging/log.h"
9#include "core/hle/config_mem.h" 8#include "core/hle/config_mem.h"
@@ -28,32 +27,39 @@ void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
28 27
29void WaitObject::RemoveWaitingThread(Thread* thread) { 28void WaitObject::RemoveWaitingThread(Thread* thread) {
30 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); 29 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
30 // If a thread passed multiple handles to the same object,
31 // the kernel might attempt to remove the thread from the object's
32 // waiting threads list multiple times.
31 if (itr != waiting_threads.end()) 33 if (itr != waiting_threads.end())
32 waiting_threads.erase(itr); 34 waiting_threads.erase(itr);
33} 35}
34 36
35SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { 37SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
36 // Remove the threads that are ready or already running from our waitlist
37 boost::range::remove_erase_if(waiting_threads, [](const SharedPtr<Thread>& thread) {
38 return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY ||
39 thread->status == THREADSTATUS_DEAD;
40 });
41
42 // TODO(Subv): This call should be performed inside the loop below to check if an object can be
43 // acquired by a particular thread. This is useful for things like recursive locking of Mutexes.
44 if (ShouldWait())
45 return nullptr;
46
47 Thread* candidate = nullptr; 38 Thread* candidate = nullptr;
48 s32 candidate_priority = THREADPRIO_LOWEST + 1; 39 s32 candidate_priority = THREADPRIO_LOWEST + 1;
49 40
50 for (const auto& thread : waiting_threads) { 41 for (const auto& thread : waiting_threads) {
42 // The list of waiting threads must not contain threads that are not waiting to be awakened.
43 ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
44 thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
45 "Inconsistent thread statuses in waiting_threads");
46
51 if (thread->current_priority >= candidate_priority) 47 if (thread->current_priority >= candidate_priority)
52 continue; 48 continue;
53 49
54 bool ready_to_run = 50 if (ShouldWait(thread.get()))
55 std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), 51 continue;
56 [](const SharedPtr<WaitObject>& object) { return object->ShouldWait(); }); 52
53 // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
54 // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
55 bool ready_to_run = true;
56 if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
57 ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
58 [&thread](const SharedPtr<WaitObject>& object) {
59 return object->ShouldWait(thread.get());
60 });
61 }
62
57 if (ready_to_run) { 63 if (ready_to_run) {
58 candidate = thread.get(); 64 candidate = thread.get();
59 candidate_priority = thread->current_priority; 65 candidate_priority = thread->current_priority;
@@ -66,7 +72,7 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
66void WaitObject::WakeupAllWaitingThreads() { 72void WaitObject::WakeupAllWaitingThreads() {
67 while (auto thread = GetHighestPriorityReadyThread()) { 73 while (auto thread = GetHighestPriorityReadyThread()) {
68 if (!thread->IsSleepingOnWaitAll()) { 74 if (!thread->IsSleepingOnWaitAll()) {
69 Acquire(); 75 Acquire(thread.get());
70 // Set the output index of the WaitSynchronizationN call to the index of this object. 76 // Set the output index of the WaitSynchronizationN call to the index of this object.
71 if (thread->wait_set_output) { 77 if (thread->wait_set_output) {
72 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); 78 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
@@ -74,18 +80,17 @@ void WaitObject::WakeupAllWaitingThreads() {
74 } 80 }
75 } else { 81 } else {
76 for (auto& object : thread->wait_objects) { 82 for (auto& object : thread->wait_objects) {
77 object->Acquire(); 83 object->Acquire(thread.get());
78 object->RemoveWaitingThread(thread.get());
79 } 84 }
80 // Note: This case doesn't update the output index of WaitSynchronizationN. 85 // Note: This case doesn't update the output index of WaitSynchronizationN.
81 // Clear the thread's waitlist
82 thread->wait_objects.clear();
83 } 86 }
84 87
88 for (auto& object : thread->wait_objects)
89 object->RemoveWaitingThread(thread.get());
90 thread->wait_objects.clear();
91
85 thread->SetWaitSynchronizationResult(RESULT_SUCCESS); 92 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
86 thread->ResumeFromWait(); 93 thread->ResumeFromWait();
87 // Note: Removing the thread from the object's waitlist will be
88 // done by GetHighestPriorityReadyThread.
89 } 94 }
90} 95}
91 96