aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-12-09 19:20:05 -0300
committerGitHub <noreply@github.com>2020-12-09 19:20:05 -0300
commit48278905d1470f89be31668c738397f569af156a (patch)
tree2e35b0695b33c8eb723f5948e3f6f040d84cfe76 /Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
parent3484265d37732b32951709e5abfa52a260db349d (diff)
Rewrite scheduler context switch code (#1786)
* Rewrite scheduler context switch code * Fix race in UnmapIpcRestorePermission * Fix thread exit issue that could leave the scheduler in a invalid state * Change context switch method to not wait on guest thread, remove spin wait, use SignalAndWait to pass control * Remove multi-core setting (it is always on now) * Re-enable assert * Remove multicore from default config and schema * Fix race in KTimeManager
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs413
1 files changed, 142 insertions, 271 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index f523cb9c..b95b1e8e 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -4,8 +4,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Numerics;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Threading
@@ -14,17 +13,24 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
public const int MaxWaitSyncObjects = 64;
- private int _hostThreadRunning;
+ private ManualResetEvent _schedulerWaitEvent;
+
+ public ManualResetEvent SchedulerWaitEvent => _schedulerWaitEvent;
public Thread HostThread { get; private set; }
public ARMeilleure.State.ExecutionContext Context { get; private set; }
+ public KThreadContext ThreadContext { get; private set; }
+
+ public int DynamicPriority { get; set; }
public long AffinityMask { get; set; }
public long ThreadUid { get; private set; }
- public long TotalTimeRunning { get; set; }
+ private long _totalTimeRunning;
+
+ public long TotalTimeRunning => _totalTimeRunning;
public KSynchronizationObject SignaledObj { get; set; }
@@ -32,6 +38,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
private ulong _entrypoint;
private ThreadStart _customThreadStart;
+ private bool _forcedUnschedulable;
+
+ public bool IsSchedulable => _customThreadStart == null && !_forcedUnschedulable;
public ulong MutexAddress { get; set; }
@@ -65,11 +74,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public KernelResult ObjSyncResult { get; set; }
- public int DynamicPriority { get; set; }
- public int CurrentCore { get; set; }
public int BasePriority { get; set; }
public int PreferredCore { get; set; }
+ public int CurrentCore { get; set; }
+ public int ActiveCore { get; set; }
+
private long _affinityMaskOverride;
private int _preferredCoreOverride;
#pragma warning disable CS0649
@@ -86,26 +96,21 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
set => _shallBeTerminated = value ? 1 : 0;
}
+ public bool TerminationRequested => ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending;
+
public bool SyncCancelled { get; set; }
public bool WaitingSync { get; set; }
- private bool _hasExited;
+ private int _hasExited;
private bool _hasBeenInitialized;
private bool _hasBeenReleased;
public bool WaitingInArbitration { get; set; }
- private KScheduler _scheduler;
-
- private KSchedulingData _schedulingData;
-
public long LastPc { get; set; }
public KThread(KernelContext context) : base(context)
{
- _scheduler = KernelContext.Scheduler;
- _schedulingData = KernelContext.Scheduler.SchedulingData;
-
WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects];
WaitSyncHandles = new int[MaxWaitSyncObjects];
@@ -119,7 +124,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
ulong argsPtr,
ulong stackTop,
int priority,
- int defaultCpuCore,
+ int cpuCore,
KProcess owner,
ThreadType type,
ThreadStart customThreadStart = null)
@@ -129,20 +134,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
throw new ArgumentException($"Invalid thread type \"{type}\".");
}
- PreferredCore = defaultCpuCore;
+ ThreadContext = new KThreadContext();
- AffinityMask |= 1L << defaultCpuCore;
+ PreferredCore = cpuCore;
+ AffinityMask |= 1L << cpuCore;
SchedFlags = type == ThreadType.Dummy
? ThreadSchedState.Running
: ThreadSchedState.None;
- CurrentCore = PreferredCore;
-
+ ActiveCore = cpuCore;
+ ObjSyncResult = KernelResult.ThreadNotStarted;
DynamicPriority = priority;
BasePriority = priority;
-
- ObjSyncResult = KernelResult.ThreadNotStarted;
+ CurrentCore = cpuCore;
_entrypoint = entrypoint;
_customThreadStart = customThreadStart;
@@ -179,41 +184,38 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Context = CpuContext.CreateExecutionContext();
- bool isAarch32 = !Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
-
- Context.IsAarch32 = isAarch32;
+ Context.IsAarch32 = !is64Bits;
Context.SetX(0, argsPtr);
- if (isAarch32)
+ if (is64Bits)
{
- Context.SetX(13, (uint)stackTop);
+ Context.SetX(31, stackTop);
}
else
{
- Context.SetX(31, stackTop);
+ Context.SetX(13, (uint)stackTop);
}
Context.CntfrqEl0 = 19200000;
Context.Tpidr = (long)_tlsAddress;
- owner.SubscribeThreadEventHandlers(Context);
-
ThreadUid = KernelContext.NewThreadUid();
- HostThread.Name = $"HLE.HostThread.{ThreadUid}";
+ HostThread.Name = customThreadStart != null ? $"HLE.OsThread.{ThreadUid}" : $"HLE.GuestThread.{ThreadUid}";
_hasBeenInitialized = true;
if (owner != null)
{
+ owner.SubscribeThreadEventHandlers(Context);
owner.AddThread(this);
if (owner.IsPaused)
{
KernelContext.CriticalSection.Enter();
- if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
+ if (TerminationRequested)
{
KernelContext.CriticalSection.Leave();
@@ -237,7 +239,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
KernelContext.CriticalSection.Enter();
- if (!ShallBeTerminated && SchedFlags != ThreadSchedState.TerminationPending)
+ if (!TerminationRequested)
{
_forcePauseFlags |= ThreadSchedState.KernelInitPauseFlag;
@@ -253,20 +255,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
if (!ShallBeTerminated)
{
- KThread currentThread = KernelContext.Scheduler.GetCurrentThread();
+ KThread currentThread = KernelStatic.GetCurrentThread();
- while (SchedFlags != ThreadSchedState.TerminationPending &&
- currentThread.SchedFlags != ThreadSchedState.TerminationPending &&
- !currentThread.ShallBeTerminated)
+ while (SchedFlags != ThreadSchedState.TerminationPending && (currentThread == null || !currentThread.TerminationRequested))
{
if ((SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.None)
{
result = KernelResult.InvalidState;
-
break;
}
- if (currentThread._forcePauseFlags == ThreadSchedState.None)
+ if (currentThread == null || currentThread._forcePauseFlags == ThreadSchedState.None)
{
if (Owner != null && _forcePauseFlags != ThreadSchedState.None)
{
@@ -275,8 +274,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
SetNewSchedFlags(ThreadSchedState.Running);
- result = KernelResult.Success;
+ StartHostThread();
+ result = KernelResult.Success;
break;
}
else
@@ -299,28 +299,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return result;
}
- public void Exit()
- {
- // TODO: Debug event.
-
- if (Owner != null)
- {
- Owner.ResourceLimit?.Release(LimitableResource.Thread, 0, 1);
-
- _hasBeenReleased = true;
- }
-
- KernelContext.CriticalSection.Enter();
-
- _forcePauseFlags &= ~ThreadSchedState.ForcePauseMask;
-
- ExitImpl();
-
- KernelContext.CriticalSection.Leave();
-
- DecrementReferenceCount();
- }
-
public ThreadSchedState PrepareForTermination()
{
KernelContext.CriticalSection.Enter();
@@ -387,9 +365,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
do
{
- if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
+ if (TerminationRequested)
{
- KernelContext.Scheduler.ExitThread(this);
Exit();
// As the death of the thread is handled by the CPU emulator, we differ from the official kernel and return here.
@@ -398,7 +375,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KernelContext.CriticalSection.Enter();
- if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
+ if (TerminationRequested)
{
state = ThreadSchedState.TerminationPending;
}
@@ -416,200 +393,74 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
} while (state == ThreadSchedState.TerminationPending);
}
- private void ExitImpl()
+ public void Exit()
{
- KernelContext.CriticalSection.Enter();
-
- SetNewSchedFlags(ThreadSchedState.TerminationPending);
-
- _hasExited = true;
+ // TODO: Debug event.
- Signal();
+ if (Owner != null)
+ {
+ Owner.ResourceLimit?.Release(LimitableResource.Thread, 0, 1);
- KernelContext.CriticalSection.Leave();
- }
+ _hasBeenReleased = true;
+ }
- public KernelResult Sleep(long timeout)
- {
KernelContext.CriticalSection.Enter();
- if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
- {
- KernelContext.CriticalSection.Leave();
+ _forcePauseFlags &= ~ThreadSchedState.ForcePauseMask;
- return KernelResult.ThreadTerminating;
- }
+ bool decRef = ExitImpl();
- SetNewSchedFlags(ThreadSchedState.Paused);
-
- if (timeout > 0)
- {
- KernelContext.TimeManager.ScheduleFutureInvocation(this, timeout);
- }
+ Context.StopRunning();
KernelContext.CriticalSection.Leave();
- if (timeout > 0)
+ if (decRef)
{
- KernelContext.TimeManager.UnscheduleFutureInvocation(this);
+ DecrementReferenceCount();
}
-
- return 0;
}
- public void Yield()
+ private bool ExitImpl()
{
KernelContext.CriticalSection.Enter();
- if (SchedFlags != ThreadSchedState.Running)
- {
- KernelContext.CriticalSection.Leave();
-
- KernelContext.Scheduler.ContextSwitch();
-
- return;
- }
+ SetNewSchedFlags(ThreadSchedState.TerminationPending);
- if (DynamicPriority < KScheduler.PrioritiesCount)
- {
- // Move current thread to the end of the queue.
- _schedulingData.Reschedule(DynamicPriority, CurrentCore, this);
- }
+ bool decRef = Interlocked.Exchange(ref _hasExited, 1) == 0;
- _scheduler.ThreadReselectionRequested = true;
+ Signal();
KernelContext.CriticalSection.Leave();
- KernelContext.Scheduler.ContextSwitch();
+ return decRef;
}
- public void YieldWithLoadBalancing()
+ public KernelResult Sleep(long timeout)
{
KernelContext.CriticalSection.Enter();
- if (SchedFlags != ThreadSchedState.Running)
+ if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
{
KernelContext.CriticalSection.Leave();
- KernelContext.Scheduler.ContextSwitch();
-
- return;
- }
-
- int prio = DynamicPriority;
- int core = CurrentCore;
-
- KThread nextThreadOnCurrentQueue = null;
-
- if (DynamicPriority < KScheduler.PrioritiesCount)
- {
- // Move current thread to the end of the queue.
- _schedulingData.Reschedule(prio, core, this);
-
- Func<KThread, bool> predicate = x => x.DynamicPriority == prio;
-
- nextThreadOnCurrentQueue = _schedulingData.ScheduledThreads(core).FirstOrDefault(predicate);
- }
-
- IEnumerable<KThread> SuitableCandidates()
- {
- foreach (KThread thread in _schedulingData.SuggestedThreads(core))
- {
- int srcCore = thread.CurrentCore;
-
- if (srcCore >= 0)
- {
- KThread selectedSrcCore = _scheduler.CoreContexts[srcCore].SelectedThread;
-
- if (selectedSrcCore == thread || ((selectedSrcCore?.DynamicPriority ?? 2) < 2))
- {
- continue;
- }
- }
-
- // If the candidate was scheduled after the current thread, then it's not worth it,
- // unless the priority is higher than the current one.
- if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime ||
- nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
- {
- yield return thread;
- }
- }
+ return KernelResult.ThreadTerminating;
}
- KThread dst = SuitableCandidates().FirstOrDefault(x => x.DynamicPriority <= prio);
-
- if (dst != null)
- {
- _schedulingData.TransferToCore(dst.DynamicPriority, core, dst);
-
- _scheduler.ThreadReselectionRequested = true;
- }
+ SetNewSchedFlags(ThreadSchedState.Paused);
- if (this != nextThreadOnCurrentQueue)
+ if (timeout > 0)
{
- _scheduler.ThreadReselectionRequested = true;
+ KernelContext.TimeManager.ScheduleFutureInvocation(this, timeout);
}
KernelContext.CriticalSection.Leave();
- KernelContext.Scheduler.ContextSwitch();
- }
-
- public void YieldAndWaitForLoadBalancing()
- {
- KernelContext.CriticalSection.Enter();
-
- if (SchedFlags != ThreadSchedState.Running)
- {
- KernelContext.CriticalSection.Leave();
-
- KernelContext.Scheduler.ContextSwitch();
-
- return;
- }
-
- int core = CurrentCore;
-
- _schedulingData.TransferToCore(DynamicPriority, -1, this);
-
- KThread selectedThread = null;
-
- if (!_schedulingData.ScheduledThreads(core).Any())
- {
- foreach (KThread thread in _schedulingData.SuggestedThreads(core))
- {
- if (thread.CurrentCore < 0)
- {
- continue;
- }
-
- KThread firstCandidate = _schedulingData.ScheduledThreads(thread.CurrentCore).FirstOrDefault();
-
- if (firstCandidate == thread)
- {
- continue;
- }
-
- if (firstCandidate == null || firstCandidate.DynamicPriority >= 2)
- {
- _schedulingData.TransferToCore(thread.DynamicPriority, core, thread);
-
- selectedThread = thread;
- }
-
- break;
- }
- }
-
- if (selectedThread != this)
+ if (timeout > 0)
{
- _scheduler.ThreadReselectionRequested = true;
+ KernelContext.TimeManager.UnscheduleFutureInvocation(this);
}
- KernelContext.CriticalSection.Leave();
-
- KernelContext.Scheduler.ContextSwitch();
+ return 0;
}
public void SetPriority(int priority)
@@ -751,17 +602,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
if (oldAffinityMask != newAffinityMask)
{
- int oldCore = CurrentCore;
+ int oldCore = ActiveCore;
- if (CurrentCore >= 0 && ((AffinityMask >> CurrentCore) & 1) == 0)
+ if (oldCore >= 0 && ((AffinityMask >> oldCore) & 1) == 0)
{
if (PreferredCore < 0)
{
- CurrentCore = HighestSetCore(AffinityMask);
+ ActiveCore = sizeof(ulong) * 8 - 1 - BitOperations.LeadingZeroCount((ulong)AffinityMask);
}
else
{
- CurrentCore = PreferredCore;
+ ActiveCore = PreferredCore;
}
}
@@ -774,19 +625,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return KernelResult.Success;
}
- private static int HighestSetCore(long mask)
- {
- for (int core = KScheduler.CpuCoresCount - 1; core >= 0; core--)
- {
- if (((mask >> core) & 1) != 0)
- {
- return core;
- }
- }
-
- return -1;
- }
-
private void CombineForcePauseFlags()
{
ThreadSchedState oldFlags = SchedFlags;
@@ -995,92 +833,112 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return;
}
+ if (!IsSchedulable)
+ {
+ // Ensure our thread is running and we have an event.
+ StartHostThread();
+
+ // If the thread is not schedulable, we want to just run or pause
+ // it directly as we don't care about priority or the core it is
+ // running on in this case.
+ if (SchedFlags == ThreadSchedState.Running)
+ {
+ _schedulerWaitEvent.Set();
+ }
+ else
+ {
+ _schedulerWaitEvent.Reset();
+ }
+
+ return;
+ }
+
if (oldFlags == ThreadSchedState.Running)
{
// Was running, now it's stopped.
- if (CurrentCore >= 0)
+ if (ActiveCore >= 0)
{
- _schedulingData.Unschedule(DynamicPriority, CurrentCore, this);
+ KernelContext.PriorityQueue.Unschedule(DynamicPriority, ActiveCore, this);
}
for (int core = 0; core < KScheduler.CpuCoresCount; core++)
{
- if (core != CurrentCore && ((AffinityMask >> core) & 1) != 0)
+ if (core != ActiveCore && ((AffinityMask >> core) & 1) != 0)
{
- _schedulingData.Unsuggest(DynamicPriority, core, this);
+ KernelContext.PriorityQueue.Unsuggest(DynamicPriority, core, this);
}
}
}
else if (SchedFlags == ThreadSchedState.Running)
{
// Was stopped, now it's running.
- if (CurrentCore >= 0)
+ if (ActiveCore >= 0)
{
- _schedulingData.Schedule(DynamicPriority, CurrentCore, this);
+ KernelContext.PriorityQueue.Schedule(DynamicPriority, ActiveCore, this);
}
for (int core = 0; core < KScheduler.CpuCoresCount; core++)
{
- if (core != CurrentCore && ((AffinityMask >> core) & 1) != 0)
+ if (core != ActiveCore && ((AffinityMask >> core) & 1) != 0)
{
- _schedulingData.Suggest(DynamicPriority, core, this);
+ KernelContext.PriorityQueue.Suggest(DynamicPriority, core, this);
}
}
}
- _scheduler.ThreadReselectionRequested = true;
+ KernelContext.ThreadReselectionRequested = true;
}
private void AdjustSchedulingForNewPriority(int oldPriority)
{
- if (SchedFlags != ThreadSchedState.Running)
+ if (SchedFlags != ThreadSchedState.Running || !IsSchedulable)
{
return;
}
// Remove thread from the old priority queues.
- if (CurrentCore >= 0)
+ if (ActiveCore >= 0)
{
- _schedulingData.Unschedule(oldPriority, CurrentCore, this);
+ KernelContext.PriorityQueue.Unschedule(oldPriority, ActiveCore, this);
}
for (int core = 0; core < KScheduler.CpuCoresCount; core++)
{
- if (core != CurrentCore && ((AffinityMask >> core) & 1) != 0)
+ if (core != ActiveCore && ((AffinityMask >> core) & 1) != 0)
{
- _schedulingData.Unsuggest(oldPriority, core, this);
+ KernelContext.PriorityQueue.Unsuggest(oldPriority, core, this);
}
}
// Add thread to the new priority queues.
- KThread currentThread = _scheduler.GetCurrentThread();
+ KThread currentThread = KernelStatic.GetCurrentThread();
- if (CurrentCore >= 0)
+ if (ActiveCore >= 0)
{
if (currentThread == this)
{
- _schedulingData.SchedulePrepend(DynamicPriority, CurrentCore, this);
+ KernelContext.PriorityQueue.SchedulePrepend(DynamicPriority, ActiveCore, this);
}
else
{
- _schedulingData.Schedule(DynamicPriority, CurrentCore, this);
+ KernelContext.PriorityQueue.Schedule(DynamicPriority, ActiveCore, this);
}
}
for (int core = 0; core < KScheduler.CpuCoresCount; core++)
{
- if (core != CurrentCore && ((AffinityMask >> core) & 1) != 0)
+ if (core != ActiveCore && ((AffinityMask >> core) & 1) != 0)
{
- _schedulingData.Suggest(DynamicPriority, core, this);
+ KernelContext.PriorityQueue.Suggest(DynamicPriority, core, this);
}
}
- _scheduler.ThreadReselectionRequested = true;
+ KernelContext.ThreadReselectionRequested = true;
}
private void AdjustSchedulingForNewAffinity(long oldAffinityMask, int oldCore)
{
- if (SchedFlags != ThreadSchedState.Running || DynamicPriority >= KScheduler.PrioritiesCount)
+ if (SchedFlags != ThreadSchedState.Running || DynamicPriority >= KScheduler.PrioritiesCount || !IsSchedulable)
{
return;
}
@@ -1092,11 +950,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
if (core == oldCore)
{
- _schedulingData.Unschedule(DynamicPriority, core, this);
+ KernelContext.PriorityQueue.Unschedule(DynamicPriority, core, this);
}
else
{
- _schedulingData.Unsuggest(DynamicPriority, core, this);
+ KernelContext.PriorityQueue.Unsuggest(DynamicPriority, core, this);
}
}
}
@@ -1106,18 +964,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
{
if (((AffinityMask >> core) & 1) != 0)
{
- if (core == CurrentCore)
+ if (core == ActiveCore)
{
- _schedulingData.Schedule(DynamicPriority, core, this);
+ KernelContext.PriorityQueue.Schedule(DynamicPriority, core, this);
}
else
{
- _schedulingData.Suggest(DynamicPriority, core, this);
+ KernelContext.PriorityQueue.Suggest(DynamicPriority, core, this);
}
}
}
- _scheduler.ThreadReselectionRequested = true;
+ KernelContext.ThreadReselectionRequested = true;
}
public void SetEntryArguments(long argsPtr, int threadHandle)
@@ -1141,17 +999,32 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Logger.Info?.Print(LogClass.Cpu, $"Guest stack trace:\n{GetGuestStackTrace()}\n");
}
- public void Execute()
+ public void AddCpuTime(long ticks)
+ {
+ Interlocked.Add(ref _totalTimeRunning, ticks);
+ }
+
+ public void StartHostThread()
{
- if (Interlocked.CompareExchange(ref _hostThreadRunning, 1, 0) == 0)
+ if (_schedulerWaitEvent == null)
{
- HostThread.Start();
+ var schedulerWaitEvent = new ManualResetEvent(false);
+
+ if (Interlocked.Exchange(ref _schedulerWaitEvent, schedulerWaitEvent) == null)
+ {
+ HostThread.Start();
+ }
+ else
+ {
+ schedulerWaitEvent.Dispose();
+ }
}
}
private void ThreadStart()
{
- KernelStatic.SetKernelContext(KernelContext);
+ _schedulerWaitEvent.WaitOne();
+ KernelStatic.SetKernelContext(KernelContext, this);
if (_customThreadStart != null)
{
@@ -1162,20 +1035,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Owner.Context.Execute(Context, _entrypoint);
}
- KernelContext.Scheduler.ExitThread(this);
- KernelContext.Scheduler.RemoveThread(this);
-
Context.Dispose();
+ _schedulerWaitEvent.Dispose();
}
- public bool IsCurrentHostThread()
+ public void MakeUnschedulable()
{
- return Thread.CurrentThread == HostThread;
+ _forcedUnschedulable = true;
}
public override bool IsSignaled()
{
- return _hasExited;
+ return _hasExited != 0;
}
protected override void Destroy()