| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- // 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
|