kern: minor behavioral fixes to condvar/address arbiter

This commit is contained in:
Michael Scire 2020-10-12 01:05:30 -07:00
parent c547c7f0e7
commit 388f9e6455
2 changed files with 50 additions and 26 deletions

View file

@ -73,15 +73,16 @@ namespace ams::kern {
s32 num_waiters = 0; s32 num_waiters = 0;
{ {
KScopedSchedulerLock sl; KScopedSchedulerLock sl;
g_cv_arbiter_compare_thread.SetupForAddressArbiterCompare(addr, -1);
auto it = this->tree.nfind(g_cv_arbiter_compare_thread);
/* Check the userspace value. */ /* Check the userspace value. */
s32 user_value; s32 user_value;
R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory()); R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory());
R_UNLESS(user_value == value, svc::ResultInvalidState()); 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)) { while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) {
KThread *target_thread = std::addressof(*it); KThread *target_thread = std::addressof(*it);
target_thread->SetSyncedObject(nullptr, ResultSuccess()); target_thread->SetSyncedObject(nullptr, ResultSuccess());
@ -108,6 +109,33 @@ namespace ams::kern {
/* Determine the updated value. */ /* Determine the updated value. */
s32 new_value; s32 new_value;
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 {
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 {
if (count <= 0) { if (count <= 0) {
if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) { if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) {
new_value = value - 1; new_value = value - 1;
@ -116,7 +144,7 @@ namespace ams::kern {
} }
} else { } else {
auto tmp_it = it; auto tmp_it = it;
int tmp_num_waiters = 0; s32 tmp_num_waiters = 0;
while ((tmp_it != this->tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && (tmp_num_waiters < count + 1)) { while ((tmp_it != this->tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && (tmp_num_waiters < count + 1)) {
++tmp_num_waiters; ++tmp_num_waiters;
++tmp_it; ++tmp_it;
@ -130,6 +158,7 @@ namespace ams::kern {
new_value = value; new_value = value;
} }
} }
}
/* Check the userspace value. */ /* Check the userspace value. */
s32 user_value; s32 user_value;

View file

@ -205,13 +205,8 @@ namespace ams::kern {
} }
/* Close threads in the list. */ /* Close threads in the list. */
if (num_waiters > MaxThreads) { for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) {
auto it = thread_list.begin(); (*it).Close();
while (it != thread_list.end()) {
KThread *thread = std::addressof(*it);
thread->Close();
it = thread_list.erase(it);
}
} }
} }