Fix PI update KThread::waiterMutex deadlock

It was determined that deadlocks inside `KThread::UpdatePriorityInheritance` would not only arise from the first level of locking with `waitingOn->waiterMutex` but also the second level of locking with `nextThread->waiterMutex` which has now also been fixed to fallback when facing contention.
This commit is contained in:
PixelyIon 2022-08-28 20:15:08 +05:30
parent 86f6fc510e
commit 7966bfa9f6

View File

@ -296,7 +296,9 @@ namespace skyline::kernel::type {
waitingOn->priority = ownerPriority; waitingOn->priority = ownerPriority;
lock.unlock(); lock.unlock();
waiterLock.lock(); waiterLock.lock();
waiterLock.unlock();
lock.lock(); lock.lock();
waitingOn = waitThread; waitingOn = waitThread;
@ -307,7 +309,23 @@ namespace skyline::kernel::type {
auto nextThread{waitingOn->waitThread}; auto nextThread{waitingOn->waitThread};
if (nextThread) { if (nextThread) {
// We need to update the location of the owner thread in the waiter queue of the thread it's waiting on // We need to update the location of the owner thread in the waiter queue of the thread it's waiting on
std::scoped_lock nextWaiterLock{nextThread->waiterMutex}; std::unique_lock nextWaiterLock{nextThread->waiterMutex, std::try_to_lock};
if (!nextWaiterLock) {
// We want to avoid a deadlock here from the thread holding nextThread->waiterMutex waiting for waiterMutex or waitingOn->waiterMutex
waitingOn->priority = ownerPriority;
lock.unlock();
waiterLock.unlock();
nextWaiterLock.lock();
nextWaiterLock.unlock();
lock.lock();
waitingOn = waitThread;
continue;
}
auto &piWaiters{nextThread->waiters}; auto &piWaiters{nextThread->waiters};
piWaiters.erase(std::find(piWaiters.begin(), piWaiters.end(), waitingOn)); piWaiters.erase(std::find(piWaiters.begin(), piWaiters.end(), waitingOn));
piWaiters.insert(std::upper_bound(piWaiters.begin(), piWaiters.end(), currentPriority, KThread::IsHigherPriority), waitingOn); piWaiters.insert(std::upper_bound(piWaiters.begin(), piWaiters.end(), currentPriority, KThread::IsHigherPriority), waitingOn);