diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index f6856789..211796db 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -122,7 +122,7 @@ namespace skyline::kernel::type { bool isHighestPriority; { - std::scoped_lock lock{owner->waiterMutex}; + std::scoped_lock lock{owner->waiterMutex, state.thread->waiterMutex}; // We need to lock both mutexes at the same time as we mutate the owner and the current thread, the ordering of locks **must** match MutexUnlock to avoid deadlocks u32 value{}; if (__atomic_compare_exchange_n(mutex, &value, tag, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index a054f4b1..d69d32a4 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -274,7 +274,9 @@ namespace skyline::kernel::type { } void KThread::UpdatePriorityInheritance() { - auto waitingOn{waitThread}; + std::unique_lock lock{waiterMutex}; + + std::shared_ptr waitingOn{waitThread}; i8 currentPriority{priority.load()}; while (waitingOn) { i8 ownerPriority; @@ -287,7 +289,21 @@ namespace skyline::kernel::type { } while (!waitingOn->priority.compare_exchange_strong(ownerPriority, currentPriority)); if (ownerPriority != currentPriority) { - std::scoped_lock waiterLock{waitingOn->waiterMutex}; + std::unique_lock waiterLock{waitingOn->waiterMutex, std::try_to_lock}; + if (!waiterLock) { + // We want to avoid a deadlock here from the thread holding waitingOn->waiterMutex waiting for waiterMutex + // We use a fallback mechanism to avoid this, resetting the state and trying again after being able to successfully acquire waitingOn->waiterMutex once + waitingOn->priority = ownerPriority; + + lock.unlock(); + waiterLock.lock(); + + lock.lock(); + waitingOn = waitThread; + + continue; + } + auto nextThread{waitingOn->waitThread}; if (nextThread) { // We need to update the location of the owner thread in the waiter queue of the thread it's waiting on diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.h b/app/src/main/cpp/skyline/kernel/types/KThread.h index 3e79ad77..2dd8b4b9 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.h +++ b/app/src/main/cpp/skyline/kernel/types/KThread.h @@ -109,6 +109,7 @@ namespace skyline { /** * @brief Recursively updates the priority for any threads this thread might be waiting on * @note PI is performed by temporarily upgrading a thread's priority if a thread waiting on it has a higher priority to prevent priority inversion + * @note This will lock `waiterMutex` internally and it must **not** be held when calling this function */ void UpdatePriorityInheritance();