diff options
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 59 |
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 | ||
| 34 | void WaitObject::WakeupAllWaitingThreads() { | 34 | SharedPtr<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 | |||
| 64 | void 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 | ||
| 43 | const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { | 92 | const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { |