Fix WaitForAddress timeout mutex deadlock

Calling `WaitSchedule` inside the block where `syncWaiterMutex` is locked causes a race with other threads which lock the core mutex and `syncWaiterMutex` together. This commit moves the `WaitSchedule` outside the block while simply setting a flag to wait later similar to `ConditionVariableWait`'s timeout case.

Co-authored-by: Billy Laws <blaws05@gmail.com>
This commit is contained in:
PixelyIon 2022-11-27 21:52:04 +05:30 committed by Mark Collins
parent 4df3c98225
commit 626008d8e2

View File

@ -425,6 +425,7 @@ namespace skyline::kernel::type {
}
if (timeout > 0 && !state.scheduler->TimedWaitSchedule(std::chrono::nanoseconds(timeout))) {
bool shouldWait{false};
{
std::scoped_lock lock{syncWaiterMutex};
auto queue{syncWaiters.equal_range(address)};
@ -434,11 +435,16 @@ namespace skyline::kernel::type {
// We need to update the boolean flag denoting that there are no more threads waiting on this address
__atomic_store_n(address, false, __ATOMIC_SEQ_CST);
} else {
state.scheduler->WaitSchedule(false);
return {};
// If we didn't find the thread in the queue then it must have been signalled already and we should just wait
shouldWait = true;
}
}
if (shouldWait) {
state.scheduler->WaitSchedule(false);
return {};
}
state.scheduler->InsertThread(state.thread);
state.scheduler->WaitSchedule(false);