Add MutexOwner field to keep track of the thread owning the mutex, update wait list when priority changes, other tweaks

This commit is contained in:
gdkchan 2018-04-21 15:56:20 -03:00
commit 531cd678e2
4 changed files with 92 additions and 24 deletions

View file

@ -78,9 +78,9 @@ namespace Ryujinx.Core.OsHle.Handles
{ {
SchedThread = Threads[Index]; SchedThread = Threads[Index];
if (HighestPriority > SchedThread.Thread.Priority) if (HighestPriority > SchedThread.Thread.ActualPriority)
{ {
HighestPriority = SchedThread.Thread.Priority; HighestPriority = SchedThread.Thread.ActualPriority;
HighestPrioIndex = Index; HighestPrioIndex = Index;
} }
@ -289,7 +289,7 @@ namespace Ryujinx.Core.OsHle.Handles
lock (SchedLock) lock (SchedLock)
{ {
SchedulerThread SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority); SchedulerThread SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.ActualPriority);
if (IsActive(Thread) && SchedThread == null) if (IsActive(Thread) && SchedThread == null)
{ {
@ -388,7 +388,7 @@ namespace Ryujinx.Core.OsHle.Handles
Logging.Debug(LogClass.KernelScheduler, "(" + Logging.Debug(LogClass.KernelScheduler, "(" +
"ThreadId: " + Thread.ThreadId + ", " + "ThreadId: " + Thread.ThreadId + ", " +
"ProcessorId: " + Thread.ProcessorId + ", " + "ProcessorId: " + Thread.ProcessorId + ", " +
"Priority: " + Thread.Priority + ") " + Message); "Priority: " + Thread.ActualPriority + ") " + Message);
} }
public void Dispose() public void Dispose()

View file

@ -1,4 +1,5 @@
using ChocolArm64; using ChocolArm64;
using System;
namespace Ryujinx.Core.OsHle.Handles namespace Ryujinx.Core.OsHle.Handles
{ {
@ -6,18 +7,19 @@ namespace Ryujinx.Core.OsHle.Handles
{ {
public AThread Thread { get; private set; } public AThread Thread { get; private set; }
public KThread MutexOwner { get; set; }
public KThread NextMutexThread { get; set; } public KThread NextMutexThread { get; set; }
public KThread NextCondVarThread { get; set; } public KThread NextCondVarThread { get; set; }
public long MutexAddress { get; set; } public long MutexAddress { get; set; }
public long CondVarAddress { get; set; } public long CondVarAddress { get; set; }
public int ActualPriority { get; private set; }
public int WantedPriority { get; private set; }
public int ProcessorId { get; private set; } public int ProcessorId { get; private set; }
public int Priority { get; private set; }
private int DesiredPriority;
public int WaitHandle { get; set; } public int WaitHandle { get; set; }
public int ThreadId => Thread.ThreadId; public int ThreadId => Thread.ThreadId;
@ -32,21 +34,79 @@ namespace Ryujinx.Core.OsHle.Handles
public void SetPriority(int Priority) public void SetPriority(int Priority)
{ {
this.Priority = DesiredPriority = Priority; ActualPriority = WantedPriority = Priority;
UpdatePriority(); UpdatePriority();
} }
public void ResetPriority()
{
Priority = DesiredPriority;
}
public void UpdatePriority() public void UpdatePriority()
{ {
if (Priority > (NextMutexThread?.Priority ?? Priority)) int OldPriority = ActualPriority;
int CurrPriority = WantedPriority;
if (NextMutexThread != null && CurrPriority > NextMutexThread.WantedPriority)
{ {
Priority = NextMutexThread.Priority; CurrPriority = NextMutexThread.WantedPriority;
}
if (CurrPriority != OldPriority)
{
ActualPriority = CurrPriority;
UpdateWaitList();
MutexOwner?.UpdatePriority();
}
}
private void UpdateWaitList()
{
KThread OwnerThread = MutexOwner;
if (OwnerThread != null)
{
//The MutexOwner field should only be non null when the thread is
//waiting for the lock, and the lock belongs to another thread.
if (OwnerThread == this)
{
throw new InvalidOperationException();
}
lock (OwnerThread)
{
//Remove itself from the list.
KThread CurrThread = OwnerThread;
while (CurrThread.NextMutexThread != null)
{
if (CurrThread.NextMutexThread == this)
{
CurrThread.NextMutexThread = NextMutexThread;
break;
}
CurrThread = CurrThread.NextMutexThread;
}
//Re-add taking new priority into account.
CurrThread = OwnerThread;
while (CurrThread.NextMutexThread != null)
{
if (CurrThread.NextMutexThread.ActualPriority < ActualPriority)
{
break;
}
CurrThread = CurrThread.NextMutexThread;
}
NextMutexThread = CurrThread.NextMutexThread;
CurrThread.NextMutexThread = this;
}
} }
} }
} }

View file

@ -91,7 +91,7 @@ namespace Ryujinx.Core.OsHle.Kernel
if (CurrThread != null) if (CurrThread != null)
{ {
ThreadState.X0 = 0; ThreadState.X0 = 0;
ThreadState.X1 = (ulong)CurrThread.Priority; ThreadState.X1 = (ulong)CurrThread.ActualPriority;
} }
else else
{ {

View file

@ -193,7 +193,7 @@ namespace Ryujinx.Core.OsHle.Kernel
//If no threads are waiting for the lock, then it should be null. //If no threads are waiting for the lock, then it should be null.
KThread OwnerThread = CurrThread.NextMutexThread; KThread OwnerThread = CurrThread.NextMutexThread;
while (OwnerThread?.NextMutexThread != null && OwnerThread.MutexAddress != MutexAddress) while (OwnerThread != null && OwnerThread.MutexAddress != MutexAddress)
{ {
OwnerThread = OwnerThread.NextMutexThread; OwnerThread = OwnerThread.NextMutexThread;
} }
@ -210,7 +210,9 @@ namespace Ryujinx.Core.OsHle.Kernel
OwnerThread.MutexAddress = 0; OwnerThread.MutexAddress = 0;
OwnerThread.CondVarAddress = 0; OwnerThread.CondVarAddress = 0;
OwnerThread.ResetPriority(); OwnerThread.MutexOwner = null;
OwnerThread.UpdatePriority();
Process.Scheduler.WakeUp(OwnerThread); Process.Scheduler.WakeUp(OwnerThread);
@ -246,7 +248,7 @@ namespace Ryujinx.Core.OsHle.Kernel
while (CurrThread.NextCondVarThread != null) while (CurrThread.NextCondVarThread != null)
{ {
if (CurrThread.NextCondVarThread.Priority < WaitThread.Priority) if (CurrThread.NextCondVarThread.ActualPriority < WaitThread.ActualPriority)
{ {
break; break;
} }
@ -315,18 +317,22 @@ namespace Ryujinx.Core.OsHle.Kernel
if (MutexValue == 0) if (MutexValue == 0)
{ {
//Give the lock to this thread.
Process.Memory.WriteInt32(CurrThread.MutexAddress, CurrThread.WaitHandle); Process.Memory.WriteInt32(CurrThread.MutexAddress, CurrThread.WaitHandle);
CurrThread.WaitHandle = 0; CurrThread.WaitHandle = 0;
CurrThread.MutexAddress = 0; CurrThread.MutexAddress = 0;
CurrThread.CondVarAddress = 0; CurrThread.CondVarAddress = 0;
CurrThread.ResetPriority(); CurrThread.MutexOwner = null;
CurrThread.UpdatePriority();
Process.Scheduler.WakeUp(CurrThread); Process.Scheduler.WakeUp(CurrThread);
} }
else else
{ {
//Wait until the lock is released.
InsertWaitingMutexThread(MutexValue, CurrThread); InsertWaitingMutexThread(MutexValue, CurrThread);
MutexValue |= MutexHasListenersMask; MutexValue |= MutexHasListenersMask;
@ -356,6 +362,8 @@ namespace Ryujinx.Core.OsHle.Kernel
return; return;
} }
WaitThread.MutexOwner = OwnerThread;
lock (OwnerThread) lock (OwnerThread)
{ {
KThread CurrThread = OwnerThread; KThread CurrThread = OwnerThread;
@ -367,7 +375,7 @@ namespace Ryujinx.Core.OsHle.Kernel
return; return;
} }
if (CurrThread.NextMutexThread.Priority < WaitThread.Priority) if (CurrThread.NextMutexThread.ActualPriority < WaitThread.ActualPriority)
{ {
break; break;
} }
@ -384,10 +392,10 @@ namespace Ryujinx.Core.OsHle.Kernel
WaitThread.NextMutexThread = CurrThread.NextMutexThread; WaitThread.NextMutexThread = CurrThread.NextMutexThread;
CurrThread.NextMutexThread = WaitThread; CurrThread.NextMutexThread = WaitThread;
CurrThread.UpdatePriority();
} }
} }
OwnerThread.UpdatePriority();
} }
private void AcquireMutexValue(long MutexAddress) private void AcquireMutexValue(long MutexAddress)