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:
parent
babfcde885
commit
531cd678e2
4 changed files with 92 additions and 24 deletions
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue