Merge pull request #2266 from FernandoS27/arbitration

Kernel: Fixes to Arbitration and SignalProcessWideKey Management
This commit is contained in:
bunnei 2019-03-28 21:42:24 -04:00 committed by GitHub
commit f770c17d01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 22 additions and 14 deletions

View File

@ -26,7 +26,7 @@ void WakeThreads(const std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_
// them all. // them all.
std::size_t last = waiting_threads.size(); std::size_t last = waiting_threads.size();
if (num_to_wake > 0) { if (num_to_wake > 0) {
last = num_to_wake; last = std::min(last, static_cast<std::size_t>(num_to_wake));
} }
// Signal the waiting threads. // Signal the waiting threads.
@ -90,9 +90,9 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a
// Determine the modified value depending on the waiting count. // Determine the modified value depending on the waiting count.
s32 updated_value; s32 updated_value;
if (waiting_threads.empty()) { if (waiting_threads.empty()) {
updated_value = value - 1;
} else if (num_to_wake <= 0 || waiting_threads.size() <= static_cast<u32>(num_to_wake)) {
updated_value = value + 1; updated_value = value + 1;
} else if (num_to_wake <= 0 || waiting_threads.size() <= static_cast<u32>(num_to_wake)) {
updated_value = value - 1;
} else { } else {
updated_value = value; updated_value = value;
} }

View File

@ -62,7 +62,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
if (thread->GetMutexWaitAddress() != 0 || thread->GetCondVarWaitAddress() != 0 || if (thread->GetMutexWaitAddress() != 0 || thread->GetCondVarWaitAddress() != 0 ||
thread->GetWaitHandle() != 0) { thread->GetWaitHandle() != 0) {
ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex ||
thread->GetStatus() == ThreadStatus::WaitCondVar);
thread->SetMutexWaitAddress(0); thread->SetMutexWaitAddress(0);
thread->SetCondVarWaitAddress(0); thread->SetCondVarWaitAddress(0);
thread->SetWaitHandle(0); thread->SetWaitHandle(0);

View File

@ -1353,7 +1353,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
current_thread->SetCondVarWaitAddress(condition_variable_addr); current_thread->SetCondVarWaitAddress(condition_variable_addr);
current_thread->SetMutexWaitAddress(mutex_addr); current_thread->SetMutexWaitAddress(mutex_addr);
current_thread->SetWaitHandle(thread_handle); current_thread->SetWaitHandle(thread_handle);
current_thread->SetStatus(ThreadStatus::WaitMutex); current_thread->SetStatus(ThreadStatus::WaitCondVar);
current_thread->InvalidateWakeupCallback(); current_thread->InvalidateWakeupCallback();
current_thread->WakeAfterDelay(nano_seconds); current_thread->WakeAfterDelay(nano_seconds);
@ -1397,10 +1397,10 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
// them all. // them all.
std::size_t last = waiting_threads.size(); std::size_t last = waiting_threads.size();
if (target != -1) if (target != -1)
last = target; last = std::min(waiting_threads.size(), static_cast<std::size_t>(target));
// If there are no threads waiting on this condition variable, just exit // If there are no threads waiting on this condition variable, just exit
if (last > waiting_threads.size()) if (last == 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
for (std::size_t index = 0; index < last; ++index) { for (std::size_t index = 0; index < last; ++index) {
@ -1408,6 +1408,9 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr);
// liberate Cond Var Thread.
thread->SetCondVarWaitAddress(0);
std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex(); std::size_t current_core = Core::System::GetInstance().CurrentCoreIndex();
auto& monitor = Core::System::GetInstance().Monitor(); auto& monitor = Core::System::GetInstance().Monitor();
@ -1426,10 +1429,9 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
} }
} while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(), } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(),
thread->GetWaitHandle())); thread->GetWaitHandle()));
if (mutex_val == 0) { if (mutex_val == 0) {
// We were able to acquire the mutex, resume this thread. // We were able to acquire the mutex, resume this thread.
ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
thread->ResumeFromWait(); thread->ResumeFromWait();
auto* const lock_owner = thread->GetLockOwner(); auto* const lock_owner = thread->GetLockOwner();
@ -1439,8 +1441,8 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
thread->SetLockOwner(nullptr); thread->SetLockOwner(nullptr);
thread->SetMutexWaitAddress(0); thread->SetMutexWaitAddress(0);
thread->SetCondVarWaitAddress(0);
thread->SetWaitHandle(0); thread->SetWaitHandle(0);
Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
} else { } else {
// Atomically signal that the mutex now has a waiting thread. // Atomically signal that the mutex now has a waiting thread.
do { do {
@ -1459,12 +1461,11 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
auto owner = handle_table.Get<Thread>(owner_handle); auto owner = handle_table.Get<Thread>(owner_handle);
ASSERT(owner); ASSERT(owner);
ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
thread->InvalidateWakeupCallback(); thread->InvalidateWakeupCallback();
thread->SetStatus(ThreadStatus::WaitMutex);
owner->AddMutexWaiter(thread); owner->AddMutexWaiter(thread);
Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
} }
} }

View File

@ -105,6 +105,7 @@ void Thread::ResumeFromWait() {
case ThreadStatus::WaitSleep: case ThreadStatus::WaitSleep:
case ThreadStatus::WaitIPC: case ThreadStatus::WaitIPC:
case ThreadStatus::WaitMutex: case ThreadStatus::WaitMutex:
case ThreadStatus::WaitCondVar:
case ThreadStatus::WaitArb: case ThreadStatus::WaitArb:
break; break;

View File

@ -51,7 +51,8 @@ enum class ThreadStatus {
WaitIPC, ///< Waiting for the reply from an IPC request WaitIPC, ///< Waiting for the reply from an IPC request
WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true
WaitMutex, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc WaitMutex, ///< Waiting due to an ArbitrateLock svc
WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc
WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc
Dormant, ///< Created but not yet made ready Dormant, ///< Created but not yet made ready
Dead ///< Run to completion, or forcefully terminated Dead ///< Run to completion, or forcefully terminated

View File

@ -234,6 +234,9 @@ QString WaitTreeThread::GetText() const {
case Kernel::ThreadStatus::WaitMutex: case Kernel::ThreadStatus::WaitMutex:
status = tr("waiting for mutex"); status = tr("waiting for mutex");
break; break;
case Kernel::ThreadStatus::WaitCondVar:
status = tr("waiting for condition variable");
break;
case Kernel::ThreadStatus::WaitArb: case Kernel::ThreadStatus::WaitArb:
status = tr("waiting for address arbiter"); status = tr("waiting for address arbiter");
break; break;
@ -269,6 +272,7 @@ QColor WaitTreeThread::GetColor() const {
case Kernel::ThreadStatus::WaitSynchAll: case Kernel::ThreadStatus::WaitSynchAll:
case Kernel::ThreadStatus::WaitSynchAny: case Kernel::ThreadStatus::WaitSynchAny:
case Kernel::ThreadStatus::WaitMutex: case Kernel::ThreadStatus::WaitMutex:
case Kernel::ThreadStatus::WaitCondVar:
case Kernel::ThreadStatus::WaitArb: case Kernel::ThreadStatus::WaitArb:
return QColor(Qt::GlobalColor::red); return QColor(Qt::GlobalColor::red);
case Kernel::ThreadStatus::Dormant: case Kernel::ThreadStatus::Dormant: