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];
|
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()
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue