From 9c3419ebccf046e0a123e0516ea134547393e451 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 3 Apr 2015 18:40:16 -0400
Subject: [PATCH] Kernel: Implemented priority inheritance for mutexes.

---
 src/core/hle/kernel/mutex.cpp  | 10 +++++++++-
 src/core/hle/kernel/thread.cpp | 10 +++++++---
 src/core/hle/kernel/thread.h   |  6 ++++++
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index be2c49706a..ebc9e79d79 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -56,7 +56,15 @@ SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
 }
 
 bool Mutex::ShouldWait() {
-    return lock_count > 0 && holding_thread != GetCurrentThread();;
+    auto thread = GetCurrentThread();
+    bool wait = lock_count > 0 && holding_thread != thread;
+
+    // If the holding thread of the mutex is lower priority than this thread, that thread should
+    // temporarily inherit this thread's priority
+    if (wait && thread->current_priority < holding_thread->current_priority)
+        holding_thread->BoostPriority(thread->current_priority);
+
+    return wait;
 }
 
 void Mutex::Acquire() {
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 3a1e15ac67..33d66b9867 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -156,9 +156,8 @@ static void PriorityBoostStarvedThreads() {
         u64 delta = current_ticks - thread->last_running_ticks;
 
         if (thread->status == THREADSTATUS_READY && delta > boost_timeout && !thread->idle) {
-            const s32 boost_priority = std::max(ready_queue.get_first()->current_priority - 1, 0);
-            ready_queue.move(thread, thread->current_priority, boost_priority);
-            thread->current_priority = boost_priority;
+            const s32 priority = std::max(ready_queue.get_first()->current_priority - 1, 0);
+            thread->BoostPriority(priority);
         }
     }
 }
@@ -435,6 +434,11 @@ void Thread::SetPriority(s32 priority) {
     nominal_priority = current_priority = priority;
 }
 
+void Thread::BoostPriority(s32 priority) {
+    ready_queue.move(this, current_priority, priority);
+    current_priority = priority;
+}
+
 SharedPtr<Thread> SetupIdleThread() {
     // We need to pass a few valid values to get around parameter checking in Thread::Create.
     auto thread = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0,
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 92f2c423b0..233bcbdbda 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -89,6 +89,12 @@ public:
      */
     void SetPriority(s32 priority);
 
+    /**
+     * Temporarily boosts the thread's priority until the next time it is scheduled
+     * @param priority The new priority
+     */
+    void BoostPriority(s32 priority);
+
     /**
      * Gets the thread's thread ID
      * @return The thread's ID
-- 
GitLab