diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index ef9dbafa56..6f61d526ad 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,7 +3,6 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
-#include <boost/range/algorithm_ext/erase.hpp>
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "core/hle/config_mem.h"
@@ -34,10 +33,17 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
 
 SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
     // Remove the threads that are ready or already running from our waitlist
-    boost::range::remove_erase_if(waiting_threads, [](const SharedPtr<Thread>& thread) {
-        return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY ||
-               thread->status == THREADSTATUS_DEAD;
-    });
+    auto to_remove = waiting_threads.end();
+    do {
+        to_remove = std::find_if(waiting_threads.begin(), waiting_threads.end(),
+                                 [](const SharedPtr<Thread>& thread) {
+                                    return thread->status == THREADSTATUS_RUNNING ||
+                                           thread->status == THREADSTATUS_READY ||
+                                           thread->status == THREADSTATUS_DEAD;
+        });
+        // Call RemoveWaitingThread so that child classes can override the behavior.
+        RemoveWaitingThread(to_remove->get());
+    } while (to_remove != waiting_threads.end());
 
     Thread* candidate = nullptr;
     s32 candidate_priority = THREADPRIO_LOWEST + 1;
@@ -49,9 +55,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
         if (ShouldWait(thread.get()))
             continue;
 
-        bool ready_to_run =
-            std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
-                         [&thread](const SharedPtr<WaitObject>& object) { return object->ShouldWait(thread.get()); });
+        bool ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
+                                        [&thread](const SharedPtr<WaitObject>& object) {
+                                            return object->ShouldWait(thread.get());
+                                        });
         if (ready_to_run) {
             candidate = thread.get();
             candidate_priority = thread->current_priority;
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 2680f89c9f..05097824b5 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -151,7 +151,7 @@ public:
      * Removes a thread from waiting on this object (e.g. if it was resumed already)
      * @param thread Pointer to thread to remove
      */
-    void RemoveWaitingThread(Thread* thread);
+    virtual void RemoveWaitingThread(Thread* thread);
 
     /**
      * Wake up all threads waiting on this object that can be awoken, in priority order,
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index e83717e80f..84ff651502 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -28,6 +28,23 @@ static void UpdateThreadPriority(Thread* thread) {
     thread->SetPriority(best_priority);
 }
 
+/**
+ * Elevate the mutex priority to the best priority
+ * among the priorities of all its waiting threads.
+ */
+static void UpdateMutexPriority(Mutex* mutex) {
+    s32 best_priority = THREADPRIO_LOWEST;
+    for (auto& waiter : mutex->GetWaitingThreads()) {
+        if (waiter->current_priority < best_priority)
+            best_priority = waiter->current_priority;
+    }
+
+    if (best_priority != mutex->priority) {
+        mutex->priority = best_priority;
+        UpdateThreadPriority(mutex->holding_thread.get());
+    }
+}
+
 void ReleaseThreadMutexes(Thread* thread) {
     for (auto& mtx : thread->held_mutexes) {
         mtx->lock_count = 0;
@@ -93,20 +110,12 @@ void Mutex::Release() {
 
 void Mutex::AddWaitingThread(SharedPtr<Thread> thread) {
     WaitObject::AddWaitingThread(thread);
+    UpdateMutexPriority(this);
+}
 
-    // Elevate the mutex priority to the best priority
-    // among the priorities of all its waiting threads.
-
-    s32 best_priority = THREADPRIO_LOWEST;
-    for (auto& waiter : GetWaitingThreads()) {
-        if (waiter->current_priority < best_priority)
-            best_priority = waiter->current_priority;
-    }
-
-    if (best_priority != priority) {
-        priority = best_priority;
-        UpdateThreadPriority(holding_thread.get());
-    }
+void Mutex::RemoveWaitingThread(Thread* thread) {
+    WaitObject::RemoveWaitingThread(thread);
+    UpdateMutexPriority(this);
 }
 
 } // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 3e6adeb179..31f9205167 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -43,6 +43,7 @@ public:
     void Acquire(Thread* thread) override;
 
     void AddWaitingThread(SharedPtr<Thread> thread) override;
+    void RemoveWaitingThread(Thread* thread) override;
 
     void Release();
 
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 5d63593446..b6e34a9e9a 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -373,8 +373,9 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha
         return ERR_SYNC_TIMEOUT;
     } else {
         // Find the first object that is acquirable in the provided list of objects
-        auto itr = std::find_if(objects.begin(), objects.end(),
-                                [thread](const ObjectPtr& object) { return !object->ShouldWait(thread); });
+        auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
+            return !object->ShouldWait(thread);
+        });
 
         if (itr != objects.end()) {
             // We found a ready object, acquire it and set the result value