|
|
@@ -17,10 +17,10 @@
|
|
|
#include "core/memory.h"
|
|
|
|
|
|
namespace Kernel {
|
|
|
-namespace {
|
|
|
+
|
|
|
// Wake up num_to_wake (or all) threads in a vector.
|
|
|
-void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s32 num_to_wake) {
|
|
|
- auto& system = Core::System::GetInstance();
|
|
|
+void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads,
|
|
|
+ s32 num_to_wake) {
|
|
|
// Only process up to 'target' threads, unless 'target' is <= 0, in which case process
|
|
|
// them all.
|
|
|
std::size_t last = waiting_threads.size();
|
|
|
@@ -32,12 +32,12 @@ void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s3
|
|
|
for (std::size_t i = 0; i < last; i++) {
|
|
|
ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb);
|
|
|
waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
|
|
+ RemoveThread(waiting_threads[i]);
|
|
|
waiting_threads[i]->SetArbiterWaitAddress(0);
|
|
|
waiting_threads[i]->ResumeFromWait();
|
|
|
system.PrepareReschedule(waiting_threads[i]->GetProcessorID());
|
|
|
}
|
|
|
}
|
|
|
-} // Anonymous namespace
|
|
|
|
|
|
AddressArbiter::AddressArbiter(Core::System& system) : system{system} {}
|
|
|
AddressArbiter::~AddressArbiter() = default;
|
|
|
@@ -184,6 +184,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
|
|
|
ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) {
|
|
|
Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
|
|
|
current_thread->SetArbiterWaitAddress(address);
|
|
|
+ InsertThread(SharedFrom(current_thread));
|
|
|
current_thread->SetStatus(ThreadStatus::WaitArb);
|
|
|
current_thread->InvalidateWakeupCallback();
|
|
|
current_thread->WakeAfterDelay(timeout);
|
|
|
@@ -192,26 +193,51 @@ ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) {
|
|
|
return RESULT_TIMEOUT;
|
|
|
}
|
|
|
|
|
|
-std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(
|
|
|
- VAddr address) const {
|
|
|
-
|
|
|
- // Retrieve all threads that are waiting for this address.
|
|
|
- std::vector<std::shared_ptr<Thread>> threads;
|
|
|
- const auto& scheduler = system.GlobalScheduler();
|
|
|
- const auto& thread_list = scheduler.GetThreadList();
|
|
|
+void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) {
|
|
|
+ ASSERT(thread->GetStatus() == ThreadStatus::WaitArb);
|
|
|
+ RemoveThread(thread);
|
|
|
+ thread->SetArbiterWaitAddress(0);
|
|
|
+}
|
|
|
|
|
|
- for (const auto& thread : thread_list) {
|
|
|
- if (thread->GetArbiterWaitAddress() == address) {
|
|
|
- threads.push_back(thread);
|
|
|
+void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) {
|
|
|
+ const VAddr arb_addr = thread->GetArbiterWaitAddress();
|
|
|
+ std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
|
|
|
+ auto it = thread_list.begin();
|
|
|
+ while (it != thread_list.end()) {
|
|
|
+ const std::shared_ptr<Thread>& current_thread = *it;
|
|
|
+ if (current_thread->GetPriority() >= thread->GetPriority()) {
|
|
|
+ thread_list.insert(it, thread);
|
|
|
+ return;
|
|
|
}
|
|
|
+ ++it;
|
|
|
}
|
|
|
+ thread_list.push_back(std::move(thread));
|
|
|
+}
|
|
|
|
|
|
- // Sort them by priority, such that the highest priority ones come first.
|
|
|
- std::sort(threads.begin(), threads.end(),
|
|
|
- [](const std::shared_ptr<Thread>& lhs, const std::shared_ptr<Thread>& rhs) {
|
|
|
- return lhs->GetPriority() < rhs->GetPriority();
|
|
|
- });
|
|
|
+void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) {
|
|
|
+ const VAddr arb_addr = thread->GetArbiterWaitAddress();
|
|
|
+ std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
|
|
|
+ auto it = thread_list.begin();
|
|
|
+ while (it != thread_list.end()) {
|
|
|
+ const std::shared_ptr<Thread>& current_thread = *it;
|
|
|
+ if (current_thread.get() == thread.get()) {
|
|
|
+ thread_list.erase(it);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ++it;
|
|
|
+ }
|
|
|
+ UNREACHABLE();
|
|
|
+}
|
|
|
|
|
|
- return threads;
|
|
|
+std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) {
|
|
|
+ std::vector<std::shared_ptr<Thread>> result;
|
|
|
+ std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[address];
|
|
|
+ auto it = thread_list.begin();
|
|
|
+ while (it != thread_list.end()) {
|
|
|
+ std::shared_ptr<Thread> current_thread = *it;
|
|
|
+ result.push_back(std::move(current_thread));
|
|
|
+ ++it;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
}
|
|
|
} // namespace Kernel
|