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

View file

@ -1,4 +1,5 @@
using ChocolArm64;
using System;
namespace Ryujinx.Core.OsHle.Handles
{
@ -6,18 +7,19 @@ namespace Ryujinx.Core.OsHle.Handles
{
public AThread Thread { get; private set; }
public KThread MutexOwner { get; set; }
public KThread NextMutexThread { get; set; }
public KThread NextCondVarThread { get; set; }
public long MutexAddress { 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 Priority { get; private set; }
private int DesiredPriority;
public int WaitHandle { get; set; }
public int ThreadId => Thread.ThreadId;
@ -32,21 +34,79 @@ namespace Ryujinx.Core.OsHle.Handles
public void SetPriority(int Priority)
{
this.Priority = DesiredPriority = Priority;
ActualPriority = WantedPriority = Priority;
UpdatePriority();
}
public void ResetPriority()
{
Priority = DesiredPriority;
}
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)
{
ThreadState.X0 = 0;
ThreadState.X1 = (ulong)CurrThread.Priority;
ThreadState.X1 = (ulong)CurrThread.ActualPriority;
}
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.
KThread OwnerThread = CurrThread.NextMutexThread;
while (OwnerThread?.NextMutexThread != null && OwnerThread.MutexAddress != MutexAddress)
while (OwnerThread != null && OwnerThread.MutexAddress != MutexAddress)
{
OwnerThread = OwnerThread.NextMutexThread;
}
@ -210,7 +210,9 @@ namespace Ryujinx.Core.OsHle.Kernel
OwnerThread.MutexAddress = 0;
OwnerThread.CondVarAddress = 0;
OwnerThread.ResetPriority();
OwnerThread.MutexOwner = null;
OwnerThread.UpdatePriority();
Process.Scheduler.WakeUp(OwnerThread);
@ -246,7 +248,7 @@ namespace Ryujinx.Core.OsHle.Kernel
while (CurrThread.NextCondVarThread != null)
{
if (CurrThread.NextCondVarThread.Priority < WaitThread.Priority)
if (CurrThread.NextCondVarThread.ActualPriority < WaitThread.ActualPriority)
{
break;
}
@ -315,18 +317,22 @@ namespace Ryujinx.Core.OsHle.Kernel
if (MutexValue == 0)
{
//Give the lock to this thread.
Process.Memory.WriteInt32(CurrThread.MutexAddress, CurrThread.WaitHandle);
CurrThread.WaitHandle = 0;
CurrThread.MutexAddress = 0;
CurrThread.CondVarAddress = 0;
CurrThread.ResetPriority();
CurrThread.MutexOwner = null;
CurrThread.UpdatePriority();
Process.Scheduler.WakeUp(CurrThread);
}
else
{
//Wait until the lock is released.
InsertWaitingMutexThread(MutexValue, CurrThread);
MutexValue |= MutexHasListenersMask;
@ -356,6 +362,8 @@ namespace Ryujinx.Core.OsHle.Kernel
return;
}
WaitThread.MutexOwner = OwnerThread;
lock (OwnerThread)
{
KThread CurrThread = OwnerThread;
@ -367,7 +375,7 @@ namespace Ryujinx.Core.OsHle.Kernel
return;
}
if (CurrThread.NextMutexThread.Priority < WaitThread.Priority)
if (CurrThread.NextMutexThread.ActualPriority < WaitThread.ActualPriority)
{
break;
}
@ -384,10 +392,10 @@ namespace Ryujinx.Core.OsHle.Kernel
WaitThread.NextMutexThread = CurrThread.NextMutexThread;
CurrThread.NextMutexThread = WaitThread;
CurrThread.UpdatePriority();
}
}
OwnerThread.UpdatePriority();
}
private void AcquireMutexValue(long MutexAddress)