Some improvements to SetThreadCoreMask, simplified implementation of wait lists
This commit is contained in:
parent
9e50ed53e6
commit
ee0b14ba08
5 changed files with 199 additions and 325 deletions
|
@ -66,17 +66,21 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
SchedThread.Dispose();
|
||||
}
|
||||
|
||||
SchedulerThread NewThread = WaitingToRun.Pop(Thread.ActualCore);
|
||||
int ActualCore = Thread.ActualCore;
|
||||
|
||||
SchedulerThread NewThread = WaitingToRun.Pop(ActualCore);
|
||||
|
||||
if (NewThread == null)
|
||||
{
|
||||
Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {Thread.ActualCore}!");
|
||||
Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {ActualCore}!");
|
||||
|
||||
RemoveActiveCore(Thread.ActualCore);
|
||||
RemoveActiveCore(ActualCore);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NewThread.Thread.ActualCore = ActualCore;
|
||||
|
||||
RunThread(NewThread);
|
||||
}
|
||||
}
|
||||
|
@ -146,17 +150,21 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
{
|
||||
PrintDbgThreadInfo(Thread, "suspended.");
|
||||
|
||||
SchedulerThread SchedThread = WaitingToRun.Pop(Thread.ActualCore);
|
||||
int ActualCore = Thread.ActualCore;
|
||||
|
||||
SchedulerThread SchedThread = WaitingToRun.Pop(ActualCore);
|
||||
|
||||
if (SchedThread != null)
|
||||
{
|
||||
SchedThread.Thread.ActualCore = ActualCore;
|
||||
|
||||
RunThread(SchedThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.PrintDebug(LogClass.KernelScheduler, $"Nothing to run on core {Thread.ActualCore}!");
|
||||
|
||||
RemoveActiveCore(Thread.ActualCore);
|
||||
RemoveActiveCore(ActualCore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,9 +177,9 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
{
|
||||
lock (SchedLock)
|
||||
{
|
||||
SchedulerThread SchedThread = WaitingToRun.Pop(
|
||||
Thread.ActualCore,
|
||||
Thread.ActualPriority);
|
||||
int ActualCore = Thread.ActualCore;
|
||||
|
||||
SchedulerThread SchedThread = WaitingToRun.Pop(ActualCore, Thread.ActualPriority);
|
||||
|
||||
if (SchedThread == null)
|
||||
{
|
||||
|
@ -182,6 +190,8 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
if (SchedThread != null)
|
||||
{
|
||||
SchedThread.Thread.ActualCore = ActualCore;
|
||||
|
||||
RunThread(SchedThread);
|
||||
}
|
||||
}
|
||||
|
@ -198,24 +208,24 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
public bool TryRunning(KThread Thread)
|
||||
{
|
||||
if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
||||
//Failing to get the thread here is fine,
|
||||
//the thread may not have been started yet.
|
||||
if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
lock (SchedLock)
|
||||
{
|
||||
if (WaitingToRun.HasThread(SchedThread) && AddActiveCore(Thread))
|
||||
lock (SchedLock)
|
||||
{
|
||||
WaitingToRun.Remove(SchedThread);
|
||||
if (WaitingToRun.HasThread(SchedThread) && AddActiveCore(Thread))
|
||||
{
|
||||
WaitingToRun.Remove(SchedThread);
|
||||
|
||||
RunThread(SchedThread);
|
||||
RunThread(SchedThread);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Resume(KThread Thread)
|
||||
|
@ -289,18 +299,25 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
private bool AddActiveCore(KThread Thread)
|
||||
{
|
||||
int CoreMask;
|
||||
|
||||
lock (SchedLock)
|
||||
{
|
||||
//First, try running it on Ideal Core.
|
||||
int CoreMask = 1 << Thread.IdealCore;
|
||||
int IdealCore = Thread.IdealCore;
|
||||
|
||||
if ((ActiveCores & CoreMask) == 0)
|
||||
if (IdealCore != -1)
|
||||
{
|
||||
ActiveCores |= CoreMask;
|
||||
CoreMask = 1 << IdealCore;
|
||||
|
||||
Thread.ActualCore = Thread.IdealCore;
|
||||
if ((ActiveCores & CoreMask) == 0)
|
||||
{
|
||||
ActiveCores |= CoreMask;
|
||||
|
||||
return true;
|
||||
Thread.ActualCore = IdealCore;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//If that fails, then try running on any core allowed by Core Mask.
|
||||
|
@ -340,11 +357,12 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
private void PrintDbgThreadInfo(KThread Thread, string Message)
|
||||
{
|
||||
Log.PrintDebug(LogClass.KernelScheduler, "(" +
|
||||
"ThreadId = " + Thread.ThreadId + ", " +
|
||||
"ActualCore = " + Thread.ActualCore + ", " +
|
||||
"IdealCore = " + Thread.IdealCore + ", " +
|
||||
"ActualPriority = " + Thread.ActualPriority + ", " +
|
||||
"WantedPriority = " + Thread.WantedPriority + ") " + Message);
|
||||
"ThreadId = " + Thread.ThreadId + ", " +
|
||||
"CoreMask = 0x" + Thread.CoreMask.ToString("x1") + ", " +
|
||||
"ActualCore = " + Thread.ActualCore + ", " +
|
||||
"IdealCore = " + Thread.IdealCore + ", " +
|
||||
"ActualPriority = " + Thread.ActualPriority + ", " +
|
||||
"WantedPriority = " + Thread.WantedPriority + ") " + Message);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using ChocolArm64;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Handles
|
||||
{
|
||||
|
@ -14,16 +14,15 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
private Process Process;
|
||||
|
||||
public KThread NextMutexThread { get; set; }
|
||||
public KThread NextCondVarThread { get; set; }
|
||||
public List<KThread> MutexWaiters { get; private set; }
|
||||
|
||||
public KThread MutexOwner { get; set; }
|
||||
|
||||
public int ActualPriority { get; private set; }
|
||||
public int WantedPriority { get; private set; }
|
||||
|
||||
public int IdealCore { get; set; }
|
||||
public int ActualCore { get; set; }
|
||||
public int IdealCore { get; set; }
|
||||
|
||||
public int WaitHandle { get; set; }
|
||||
|
||||
|
@ -39,6 +38,8 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
this.Process = Process;
|
||||
this.IdealCore = IdealCore;
|
||||
|
||||
MutexWaiters = new List<KThread>();
|
||||
|
||||
CoreMask = 1 << IdealCore;
|
||||
|
||||
ActualPriority = WantedPriority = Priority;
|
||||
|
@ -57,148 +58,25 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
int CurrPriority = WantedPriority;
|
||||
|
||||
if (NextMutexThread != null && CurrPriority > NextMutexThread.WantedPriority)
|
||||
lock (Process.ThreadSyncLock)
|
||||
{
|
||||
CurrPriority = NextMutexThread.WantedPriority;
|
||||
foreach (KThread Thread in MutexWaiters)
|
||||
{
|
||||
if (CurrPriority > Thread.WantedPriority)
|
||||
{
|
||||
CurrPriority = Thread.WantedPriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrPriority != OldPriority)
|
||||
{
|
||||
ActualPriority = CurrPriority;
|
||||
|
||||
UpdateWaitLists();
|
||||
Process.Scheduler.Resort(this);
|
||||
|
||||
MutexOwner?.UpdatePriority();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateWaitLists()
|
||||
{
|
||||
UpdateMutexList();
|
||||
UpdateCondVarList();
|
||||
|
||||
Process.Scheduler.Resort(this);
|
||||
}
|
||||
|
||||
private void UpdateMutexList()
|
||||
{
|
||||
KThread OwnerThread = MutexOwner;
|
||||
|
||||
if (OwnerThread == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCondVarList()
|
||||
{
|
||||
lock (Process.ThreadArbiterListLock)
|
||||
{
|
||||
if (Process.ThreadArbiterListHead == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Remove itself from the list.
|
||||
bool Found;
|
||||
|
||||
KThread CurrThread = Process.ThreadArbiterListHead;
|
||||
|
||||
if (Found = (Process.ThreadArbiterListHead == this))
|
||||
{
|
||||
Process.ThreadArbiterListHead = Process.ThreadArbiterListHead.NextCondVarThread;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (CurrThread.NextCondVarThread != null)
|
||||
{
|
||||
if (CurrThread.NextCondVarThread == this)
|
||||
{
|
||||
CurrThread.NextCondVarThread = NextCondVarThread;
|
||||
|
||||
Found = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
CurrThread = CurrThread.NextCondVarThread;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Re-add taking new priority into account.
|
||||
if (Process.ThreadArbiterListHead == null ||
|
||||
Process.ThreadArbiterListHead.ActualPriority > ActualPriority)
|
||||
{
|
||||
NextCondVarThread = Process.ThreadArbiterListHead;
|
||||
|
||||
Process.ThreadArbiterListHead = this;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CurrThread = Process.ThreadArbiterListHead;
|
||||
|
||||
while (CurrThread.NextCondVarThread != null)
|
||||
{
|
||||
if (CurrThread.NextCondVarThread.ActualPriority > ActualPriority)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CurrThread = CurrThread.NextCondVarThread;
|
||||
}
|
||||
|
||||
NextCondVarThread = CurrThread.NextCondVarThread;
|
||||
|
||||
CurrThread.NextCondVarThread = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue