From 998b9a9525013832c593f8f469ea0ae9565985b7 Mon Sep 17 00:00:00 2001 From: GPUCode <47210458+GPUCode@users.noreply.github.com> Date: Sun, 5 Nov 2023 00:20:55 +0200 Subject: [PATCH] kernel: Add ticks to low priority threads that arbitrate zero threads (#7096) --- src/core/hle/kernel/address_arbiter.cpp | 37 +++++++++++++++++-------- src/core/hle/kernel/address_arbiter.h | 4 +-- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index a8f30bad0c..4d1ab4909c 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -6,7 +6,6 @@ #include "common/archives.h" #include "common/common_types.h" #include "common/logging/log.h" -#include "core/global.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" @@ -21,7 +20,7 @@ void AddressArbiter::WaitThread(std::shared_ptr thread, VAddr wait_addre waiting_threads.emplace_back(std::move(thread)); } -void AddressArbiter::ResumeAllThreads(VAddr address) { +u64 AddressArbiter::ResumeAllThreads(VAddr address) { // Determine which threads are waiting on this address, those should be woken up. auto itr = std::stable_partition(waiting_threads.begin(), waiting_threads.end(), [address](const auto& thread) { @@ -31,13 +30,15 @@ void AddressArbiter::ResumeAllThreads(VAddr address) { }); // Wake up all the found threads + const u64 num_threads = std::distance(itr, waiting_threads.end()); std::for_each(itr, waiting_threads.end(), [](auto& thread) { thread->ResumeFromWait(); }); // Remove the woken up threads from the wait list. waiting_threads.erase(itr, waiting_threads.end()); + return num_threads; } -std::shared_ptr AddressArbiter::ResumeHighestPriorityThread(VAddr address) { +bool AddressArbiter::ResumeHighestPriorityThread(VAddr address) { // Determine which threads are waiting on this address, those should be considered for wakeup. auto matches_start = std::stable_partition( waiting_threads.begin(), waiting_threads.end(), [address](const auto& thread) { @@ -54,14 +55,15 @@ std::shared_ptr AddressArbiter::ResumeHighestPriorityThread(VAddr addres return lhs->current_priority < rhs->current_priority; }); - if (itr == waiting_threads.end()) - return nullptr; + if (itr == waiting_threads.end()) { + return false; + } auto thread = *itr; thread->ResumeFromWait(); - waiting_threads.erase(itr); - return thread; + + return true; } AddressArbiter::AddressArbiter(KernelSystem& kernel) @@ -107,17 +109,28 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr thread, Arbi switch (type) { // Signal thread(s) waiting for arbitrate address... - case ArbitrationType::Signal: + case ArbitrationType::Signal: { + u64 num_threads{}; + // Negative value means resume all threads if (value < 0) { - ResumeAllThreads(address); + num_threads = ResumeAllThreads(address); } else { // Resume first N threads - for (int i = 0; i < value; i++) - ResumeHighestPriorityThread(address); + for (s32 i = 0; i < value; i++) { + num_threads += ResumeHighestPriorityThread(address); + } + } + + // Prevents lag from low priority threads that spam svcArbitrateAddress and wake no threads + // The tick count is taken directly from official HOS kernel. The priority value is one less + // than official kernel as the affected FMV threads dont meet the priority threshold of 50. + // TODO: Revisit this when scheduler is rewritten and adjust if there isn't a problem there. + if (num_threads == 0 && thread->current_priority >= 49) { + kernel.current_cpu->GetTimer().AddTicks(1614u); } break; - + } // Wait current thread (acquire the arbiter)... case ArbitrationType::WaitIfLessThan: if ((s32)kernel.memory.Read32(address) < value) { diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 893df5408e..1cc477042d 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -65,11 +65,11 @@ private: void WaitThread(std::shared_ptr thread, VAddr wait_address); /// Resume all threads found to be waiting on the address under this address arbiter - void ResumeAllThreads(VAddr address); + u64 ResumeAllThreads(VAddr address); /// Resume one thread found to be waiting on the address under this address arbiter and return /// the resumed thread. - std::shared_ptr ResumeHighestPriorityThread(VAddr address); + bool ResumeHighestPriorityThread(VAddr address); /// Threads waiting for the address arbiter to be signaled. std::vector> waiting_threads;