From 388f9e6455519e92e1abb5f2d19b73cc7a471e56 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 12 Oct 2020 01:05:30 -0700 Subject: [PATCH] kern: minor behavioral fixes to condvar/address arbiter --- .../source/kern_k_address_arbiter.cpp | 67 +++++++++++++------ .../source/kern_k_condition_variable.cpp | 9 +-- 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/libraries/libmesosphere/source/kern_k_address_arbiter.cpp b/libraries/libmesosphere/source/kern_k_address_arbiter.cpp index dfcd40883..171fd6d33 100644 --- a/libraries/libmesosphere/source/kern_k_address_arbiter.cpp +++ b/libraries/libmesosphere/source/kern_k_address_arbiter.cpp @@ -73,15 +73,16 @@ namespace ams::kern { s32 num_waiters = 0; { KScopedSchedulerLock sl; - g_cv_arbiter_compare_thread.SetupForAddressArbiterCompare(addr, -1); - - auto it = this->tree.nfind(g_cv_arbiter_compare_thread); /* Check the userspace value. */ s32 user_value; R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory()); R_UNLESS(user_value == value, svc::ResultInvalidState()); + g_cv_arbiter_compare_thread.SetupForAddressArbiterCompare(addr, -1); + + auto it = this->tree.nfind(g_cv_arbiter_compare_thread); + while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { KThread *target_thread = std::addressof(*it); target_thread->SetSyncedObject(nullptr, ResultSuccess()); @@ -108,26 +109,54 @@ namespace ams::kern { /* Determine the updated value. */ s32 new_value; - if (count <= 0) { - if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) { - new_value = value - 1; + if (GetTargetFirmware() >= TargetFirmware_7_0_0) { + if (count <= 0) { + if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) { + new_value = value - 2; + } else { + new_value = value + 1; + } } else { - new_value = value + 1; + if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) { + auto tmp_it = it; + s32 tmp_num_waiters = 0; + while ((++tmp_it != this->tree.end()) && (tmp_it->GetAddressArbiterKey() == addr)) { + if ((tmp_num_waiters++) >= count) { + break; + } + } + + if (tmp_num_waiters < count) { + new_value = value - 1; + } else { + new_value = value; + } + } else { + new_value = value + 1; + } } } else { - auto tmp_it = it; - int tmp_num_waiters = 0; - while ((tmp_it != this->tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && (tmp_num_waiters < count + 1)) { - ++tmp_num_waiters; - ++tmp_it; - } - - if (tmp_num_waiters == 0) { - new_value = value + 1; - } else if (tmp_num_waiters <= count) { - new_value = value - 1; + if (count <= 0) { + if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) { + new_value = value - 1; + } else { + new_value = value + 1; + } } else { - new_value = value; + auto tmp_it = it; + s32 tmp_num_waiters = 0; + while ((tmp_it != this->tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && (tmp_num_waiters < count + 1)) { + ++tmp_num_waiters; + ++tmp_it; + } + + if (tmp_num_waiters == 0) { + new_value = value + 1; + } else if (tmp_num_waiters <= count) { + new_value = value - 1; + } else { + new_value = value; + } } } diff --git a/libraries/libmesosphere/source/kern_k_condition_variable.cpp b/libraries/libmesosphere/source/kern_k_condition_variable.cpp index 270c3c8ac..dc768e43c 100644 --- a/libraries/libmesosphere/source/kern_k_condition_variable.cpp +++ b/libraries/libmesosphere/source/kern_k_condition_variable.cpp @@ -205,13 +205,8 @@ namespace ams::kern { } /* Close threads in the list. */ - if (num_waiters > MaxThreads) { - auto it = thread_list.begin(); - while (it != thread_list.end()) { - KThread *thread = std::addressof(*it); - thread->Close(); - it = thread_list.erase(it); - } + for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) { + (*it).Close(); } }