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.cpp59
1 files changed, 54 insertions, 5 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0c8752670..be7a5a6d8 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -31,13 +31,62 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
31 waiting_threads.erase(itr); 31 waiting_threads.erase(itr);
32} 32}
33 33
34void WaitObject::WakeupAllWaitingThreads() { 34SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
35 for (auto thread : waiting_threads) 35 // Remove the threads that are ready or already running from our waitlist
36 thread->ResumeFromWait(); 36 waiting_threads.erase(std::remove_if(waiting_threads.begin(), waiting_threads.end(), [](SharedPtr<Thread> thread) -> bool {
37 return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY;
38 }), waiting_threads.end());
39
40 if (waiting_threads.empty())
41 return nullptr;
37 42
38 waiting_threads.clear(); 43 auto candidate_threads = waiting_threads;
39 44
40 HLE::Reschedule(__func__); 45 // Eliminate all threads that are waiting on more than one object, and not all of them are ready
46 candidate_threads.erase(std::remove_if(candidate_threads.begin(), candidate_threads.end(), [](SharedPtr<Thread> thread) -> bool {
47 for (auto object : thread->wait_objects)
48 if (object->ShouldWait())
49 return true;
50 return false;
51 }), candidate_threads.end());
52
53 // Return the thread with the lowest priority value (The one with the highest priority)
54 auto thread_itr = std::min_element(candidate_threads.begin(), candidate_threads.end(), [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
55 return lhs->current_priority < rhs->current_priority;
56 });
57
58 if (thread_itr == candidate_threads.end())
59 return nullptr;
60
61 return *thread_itr;
62}
63
64void WaitObject::WakeupAllWaitingThreads() {
65 // Wake up all threads that can be awoken, in priority order
66 while (auto thread = GetHighestPriorityReadyThread()) {
67 if (thread->wait_objects.empty()) {
68 Acquire();
69 // Set the output index of the WaitSynchronizationN call to the index of this object.
70 if (thread->wait_set_output) {
71 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
72 thread->wait_set_output = false;
73 }
74 } else {
75 for (auto object : thread->wait_objects) {
76 object->Acquire();
77 // Remove the thread from the object's waitlist
78 object->RemoveWaitingThread(thread.get());
79 }
80 // Note: This case doesn't update the output index of WaitSynchronizationN.
81 // Clear the thread's waitlist
82 thread->wait_objects.clear();
83 }
84
85 // Set the result of the call to WaitSynchronization to RESULT_SUCCESS
86 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
87 thread->ResumeFromWait();
88 // Note: Removing the thread from the object's waitlist will be done by GetHighestPriorityReadyThread
89 }
41} 90}
42 91
43const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { 92const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {