Merge pull request #2266 from FernandoS27/arbitration
Kernel: Fixes to Arbitration and SignalProcessWideKey Management
This commit is contained in:
commit
f770c17d01
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Reference in New Issue