Remove _idleThread entirely

This commit is contained in:
riperiperi 2024-05-20 19:36:59 +01:00
commit 83f2eb9495
3 changed files with 26 additions and 52 deletions

View file

@ -31,35 +31,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
private KThread _previousThread; private KThread _previousThread;
private KThread _currentThread; private KThread _currentThread;
private readonly KThread _idleThread;
private int _coreIdleLock; private int _coreIdleLock;
private bool _idleSignalled = true; private bool _idleSignalled = true;
private bool _idleActive = true; private bool _idleActive = true;
private long _idleTimeRunning;
public KThread PreviousThread => _previousThread; public KThread PreviousThread => _previousThread;
public KThread CurrentThread => _currentThread; public KThread CurrentThread => _currentThread;
public long LastContextSwitchTime { get; private set; } public long LastContextSwitchTime { get; private set; }
public long TotalIdleTimeTicks => _idleThread.TotalTimeRunning; public long TotalIdleTimeTicks => _idleTimeRunning;
public KScheduler(KernelContext context, int coreId) public KScheduler(KernelContext context, int coreId)
{ {
_context = context; _context = context;
_coreId = coreId; _coreId = coreId;
KThread idleThread = CreateIdleThread(context, coreId); _currentThread = null;
_currentThread = idleThread;
_idleThread = idleThread;
}
private KThread CreateIdleThread(KernelContext context, int cpuCore)
{
KThread idleThread = new(context);
idleThread.Initialize(0UL, 0UL, 0UL, PrioritiesCount, cpuCore, null, ThreadType.Dummy, null);
return idleThread;
} }
public static ulong SelectThreads(KernelContext context) public static ulong SelectThreads(KernelContext context)
@ -233,7 +221,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KThread threadToSignal = context.Schedulers[coreToSignal]._currentThread; KThread threadToSignal = context.Schedulers[coreToSignal]._currentThread;
// Request the thread running on that core to stop and reschedule, if we have one. // Request the thread running on that core to stop and reschedule, if we have one.
if (threadToSignal != context.Schedulers[coreToSignal]._idleThread) if (threadToSignal != null)
{ {
threadToSignal.Context.RequestInterrupt(); threadToSignal.Context.RequestInterrupt();
} }
@ -281,9 +269,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
_state.NeedsScheduling = false; _state.NeedsScheduling = false;
Thread.MemoryBarrier(); Thread.MemoryBarrier();
KThread nextThread = PickNextThread(_idleThread, _state.SelectedThread); KThread nextThread = PickNextThread(null, _state.SelectedThread);
if (_idleThread != nextThread) if (nextThread != null)
{ {
_idleActive = false; _idleActive = false;
nextThread.SchedulerWaitEvent.Set(); nextThread.SchedulerWaitEvent.Set();
@ -306,7 +294,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return; return;
} }
Debug.Assert(currentThread != _idleThread); Debug.Assert(currentThread != null);
currentThread.SchedulerWaitEvent.Reset(); currentThread.SchedulerWaitEvent.Reset();
currentThread.ThreadContext.Unlock(); currentThread.ThreadContext.Unlock();
@ -323,7 +311,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
// Wait until this thread is scheduled again, and allow the next thread to run. // Wait until this thread is scheduled again, and allow the next thread to run.
if (nextThread == _idleThread) if (nextThread == null)
{ {
ActivateIdleThread(); ActivateIdleThread();
currentThread.SchedulerWaitEvent.WaitOne(); currentThread.SchedulerWaitEvent.WaitOne();
@ -337,7 +325,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
// Allow the next thread to run. // Allow the next thread to run.
if (nextThread == _idleThread) if (nextThread == null)
{ {
ActivateIdleThread(); ActivateIdleThread();
} }
@ -385,7 +373,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
} }
else else
{ {
return _idleThread; return null;
} }
} }
else else
@ -393,7 +381,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
// The core is idle now, make sure that the idle thread can run // The core is idle now, make sure that the idle thread can run
// and switch the core when a thread is available. // and switch the core when a thread is available.
SwitchTo(currentThread, null); SwitchTo(currentThread, null);
return _idleThread; return null;
} }
_state.NeedsScheduling = false; _state.NeedsScheduling = false;
@ -404,9 +392,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
private void SwitchTo(KThread currentThread, KThread nextThread) private void SwitchTo(KThread currentThread, KThread nextThread)
{ {
KProcess currentProcess = currentThread.Owner; KProcess currentProcess = currentThread?.Owner;
nextThread ??= _idleThread;
if (currentThread != nextThread) if (currentThread != nextThread)
{ {
@ -414,7 +400,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
long currentTicks = PerformanceCounter.ElapsedTicks; long currentTicks = PerformanceCounter.ElapsedTicks;
long ticksDelta = currentTicks - previousTicks; long ticksDelta = currentTicks - previousTicks;
currentThread.AddCpuTime(ticksDelta); if (currentThread == null)
{
Interlocked.Add(ref _idleTimeRunning, ticksDelta);
}
else
{
currentThread.AddCpuTime(ticksDelta);
}
currentProcess?.AddCpuTime(ticksDelta); currentProcess?.AddCpuTime(ticksDelta);
@ -424,13 +417,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
_previousThread = !currentThread.TerminationRequested && currentThread.ActiveCore == _coreId ? currentThread : null; _previousThread = !currentThread.TerminationRequested && currentThread.ActiveCore == _coreId ? currentThread : null;
} }
else if (currentThread == _idleThread) else if (currentThread == null)
{ {
_previousThread = null; _previousThread = null;
} }
} }
if (nextThread.CurrentCore != _coreId) if (nextThread != null && nextThread.CurrentCore != _coreId)
{ {
nextThread.CurrentCore = _coreId; nextThread.CurrentCore = _coreId;
} }

View file

@ -45,9 +45,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
private ulong _entrypoint; private ulong _entrypoint;
private ThreadStart _customThreadStart; private ThreadStart _customThreadStart;
private bool _forcedUnschedulable; private bool _forcedUnschedulable;
private bool _isDummy;
public bool IsSchedulable => _customThreadStart == null && !_isDummy && !_forcedUnschedulable; public bool IsSchedulable => _customThreadStart == null && !_forcedUnschedulable;
public ulong MutexAddress { get; set; } public ulong MutexAddress { get; set; }
public int KernelWaitersCount { get; private set; } public int KernelWaitersCount { get; private set; }
@ -145,11 +144,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
PreferredCore = cpuCore; PreferredCore = cpuCore;
AffinityMask |= 1UL << cpuCore; AffinityMask |= 1UL << cpuCore;
_isDummy = type == ThreadType.Dummy; SchedFlags = ThreadSchedState.None;
SchedFlags = _isDummy
? ThreadSchedState.Running
: ThreadSchedState.None;
ActiveCore = cpuCore; ActiveCore = cpuCore;
ObjSyncResult = KernelResult.ThreadNotStarted; ObjSyncResult = KernelResult.ThreadNotStarted;
@ -187,10 +182,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
is64Bits = true; is64Bits = true;
} }
if (!_isDummy) HostThread = new Thread(ThreadStart);
{
HostThread = new Thread(ThreadStart);
}
Context = owner?.CreateExecutionContext() ?? new ProcessExecutionContext(); Context = owner?.CreateExecutionContext() ?? new ProcessExecutionContext();
@ -214,10 +206,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
ThreadUid = KernelContext.NewThreadUid(); ThreadUid = KernelContext.NewThreadUid();
if (!_isDummy) HostThread.Name = customThreadStart != null ? $"HLE.OsThread.{ThreadUid}" : $"HLE.GuestThread.{ThreadUid}";
{
HostThread.Name = customThreadStart != null ? $"HLE.OsThread.{ThreadUid}" : $"HLE.GuestThread.{ThreadUid}";
}
_hasBeenInitialized = true; _hasBeenInitialized = true;
@ -1066,8 +1055,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
// it directly as we don't care about priority or the core it is // it directly as we don't care about priority or the core it is
// running on in this case. // running on in this case.
Debug.Assert(!_isDummy);
if (SchedFlags == ThreadSchedState.Running) if (SchedFlags == ThreadSchedState.Running)
{ {
_schedulerWaitEvent.Set(); _schedulerWaitEvent.Set();
@ -1244,11 +1231,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public void StartHostThread() public void StartHostThread()
{ {
if (_isDummy)
{
throw new InvalidOperationException("Dummy threads can't start a host thread.");
}
if (_schedulerWaitEvent == null) if (_schedulerWaitEvent == null)
{ {
var schedulerWaitEvent = new ManualResetEvent(false); var schedulerWaitEvent = new ManualResetEvent(false);

View file

@ -2,7 +2,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
enum ThreadType enum ThreadType
{ {
Dummy,
Kernel, Kernel,
Kernel2, Kernel2,
User, User,