Kernel/Mutex: Propagate thread priority changes to other threads inheriting the priority via mutexes
This commit is contained in:
parent
b6a0355568
commit
d3ff5b91e1
5 changed files with 60 additions and 42 deletions
|
@ -13,38 +13,6 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
/**
|
||||
* Boost's a thread's priority to the best priority among the thread's held mutexes.
|
||||
* This prevents priority inversion via priority inheritance.
|
||||
*/
|
||||
static void UpdateThreadPriority(Thread* thread) {
|
||||
s32 best_priority = THREADPRIO_LOWEST;
|
||||
for (auto& mutex : thread->held_mutexes) {
|
||||
if (mutex->priority < best_priority)
|
||||
best_priority = mutex->priority;
|
||||
}
|
||||
|
||||
best_priority = std::min(best_priority, thread->nominal_priority);
|
||||
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;
|
||||
|
@ -83,9 +51,7 @@ void Mutex::Acquire(Thread* thread) {
|
|||
priority = thread->current_priority;
|
||||
thread->held_mutexes.insert(this);
|
||||
holding_thread = thread;
|
||||
|
||||
UpdateThreadPriority(thread);
|
||||
|
||||
thread->UpdatePriority();
|
||||
Core::System::GetInstance().PrepareReschedule();
|
||||
}
|
||||
|
||||
|
@ -100,7 +66,7 @@ void Mutex::Release() {
|
|||
// Yield to the next thread only if we've fully released the mutex
|
||||
if (lock_count == 0) {
|
||||
holding_thread->held_mutexes.erase(this);
|
||||
UpdateThreadPriority(holding_thread.get());
|
||||
holding_thread->UpdatePriority();
|
||||
holding_thread = nullptr;
|
||||
WakeupAllWaitingThreads();
|
||||
Core::System::GetInstance().PrepareReschedule();
|
||||
|
@ -110,12 +76,30 @@ void Mutex::Release() {
|
|||
|
||||
void Mutex::AddWaitingThread(SharedPtr<Thread> thread) {
|
||||
WaitObject::AddWaitingThread(thread);
|
||||
UpdateMutexPriority(this);
|
||||
thread->pending_mutexes.insert(this);
|
||||
UpdatePriority();
|
||||
}
|
||||
|
||||
void Mutex::RemoveWaitingThread(Thread* thread) {
|
||||
WaitObject::RemoveWaitingThread(thread);
|
||||
UpdateMutexPriority(this);
|
||||
thread->pending_mutexes.erase(this);
|
||||
UpdatePriority();
|
||||
}
|
||||
|
||||
void Mutex::UpdatePriority() {
|
||||
if (!holding_thread)
|
||||
return;
|
||||
|
||||
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;
|
||||
holding_thread->UpdatePriority();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue