Implement the synchronization primitives like the Horizon kernel does (#97)
* Started to work in improving the sync primitives * Some fixes * Check that the mutex address matches before waking a waiting thread * Add MutexOwner field to keep track of the thread owning the mutex, update wait list when priority changes, other tweaks * Add new priority information to the log * SvcSetThreadPriority should update just the WantedPriority
This commit is contained in:
parent
267ea14cb5
commit
90279d96ea
9 changed files with 577 additions and 375 deletions
|
@ -1,4 +1,5 @@
|
|||
using ChocolArm64;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Handles
|
||||
{
|
||||
|
@ -6,10 +7,20 @@ 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; set; }
|
||||
public int Handle { get; set; }
|
||||
public int WaitHandle { get; set; }
|
||||
|
||||
public int ThreadId => Thread.ThreadId;
|
||||
|
||||
|
@ -17,7 +28,86 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
{
|
||||
this.Thread = Thread;
|
||||
this.ProcessorId = ProcessorId;
|
||||
this.Priority = Priority;
|
||||
|
||||
ActualPriority = WantedPriority = Priority;
|
||||
}
|
||||
|
||||
public void SetPriority(int Priority)
|
||||
{
|
||||
WantedPriority = Priority;
|
||||
|
||||
UpdatePriority();
|
||||
}
|
||||
|
||||
public void UpdatePriority()
|
||||
{
|
||||
int OldPriority = ActualPriority;
|
||||
|
||||
int CurrPriority = WantedPriority;
|
||||
|
||||
if (NextMutexThread != null && CurrPriority > NextMutexThread.WantedPriority)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue