aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/KThread.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-09-18 20:36:43 -0300
committerGitHub <noreply@github.com>2018-09-18 20:36:43 -0300
commitb8133c19971c7a2026af803003fafedbdb70488e (patch)
tree84f4630e897ccd3f77b86051241a22a6cf45193d /Ryujinx.HLE/HOS/Kernel/KThread.cs
parent33e2810ef36fe0cf613aecd4c609f425aed02539 (diff)
Thread scheduler rewrite (#393)
* Started to rewrite the thread scheduler * Add a single core-like scheduling mode, enabled by default * Clear exclusive monitor on context switch * Add SetThreadActivity, misc fixes * Implement WaitForAddress and SignalToAddress svcs, misc fixes * Misc fixes (on SetActivity and Arbiter), other tweaks * Rebased * Add missing null check * Rename multicore key on config, fix UpdatePriorityInheritance * Make scheduling data MLQs private * nit: Ordering
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/KThread.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/KThread.cs873
1 files changed, 829 insertions, 44 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/KThread.cs b/Ryujinx.HLE/HOS/Kernel/KThread.cs
index 171fefc5..aecaf639 100644
--- a/Ryujinx.HLE/HOS/Kernel/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KThread.cs
@@ -1,98 +1,883 @@
using ChocolArm64;
+using System;
using System.Collections.Generic;
+using System.Linq;
+
+using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel
{
- class KThread : KSynchronizationObject
+ class KThread : KSynchronizationObject, IKFutureSchedulerObject
{
- public AThread Thread { get; private set; }
+ public AThread Context { get; private set; }
- public int CoreMask { get; set; }
+ public long AffinityMask { get; set; }
- public long MutexAddress { get; set; }
- public long CondVarAddress { get; set; }
- public long ArbiterWaitAddress { get; set; }
+ public int ThreadId { get; private set; }
- public bool CondVarSignaled { get; set; }
- public bool ArbiterSignaled { get; set; }
+ public KSynchronizationObject SignaledObj;
- private Process Process;
+ public long CondVarAddress { get; set; }
+ public long MutexAddress { get; set; }
- public List<KThread> MutexWaiters { get; private set; }
+ public Process Owner { get; private set; }
- public KThread MutexOwner { get; set; }
+ public long LastScheduledTicks { get; set; }
- public int ActualPriority { get; private set; }
- public int WantedPriority { get; private set; }
+ public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
- public int ActualCore { get; set; }
- public int ProcessorId { get; set; }
- public int IdealCore { get; set; }
+ private LinkedListNode<KThread> WithholderNode;
- public int WaitHandle { get; set; }
+ private LinkedList<KThread> MutexWaiters;
+ private LinkedListNode<KThread> MutexWaiterNode;
- public long LastPc { get; set; }
+ public KThread MutexOwner { get; private set; }
- public int ThreadId { get; private set; }
+ public int ThreadHandleForUserMutex { get; set; }
+
+ private ThreadSchedState ForcePauseFlags;
+
+ public int ObjSyncResult { get; set; }
+
+ public int DynamicPriority { get; set; }
+ public int CurrentCore { get; set; }
+ public int BasePriority { get; set; }
+ public int PreferredCore { get; set; }
+
+ private long AffinityMaskOverride;
+ private int PreferredCoreOverride;
+ private int AffinityOverrideCount;
+
+ public ThreadSchedState SchedFlags { get; private set; }
+
+ public bool ShallBeTerminated { get; private set; }
+
+ public bool SyncCancelled { get; set; }
+ public bool WaitingSync { get; set; }
+
+ private bool HasExited;
+
+ public bool WaitingInArbitration { get; set; }
+
+ private KScheduler Scheduler;
+
+ private KSchedulingData SchedulingData;
+
+ public long LastPc { get; set; }
public KThread(
AThread Thread,
Process Process,
+ Horizon System,
int ProcessorId,
int Priority,
- int ThreadId)
+ int ThreadId) : base(System)
{
- this.Thread = Thread;
- this.Process = Process;
- this.ProcessorId = ProcessorId;
- this.IdealCore = ProcessorId;
- this.ThreadId = ThreadId;
+ this.ThreadId = ThreadId;
+
+ Context = Thread;
+ Owner = Process;
+ PreferredCore = ProcessorId;
+ Scheduler = System.Scheduler;
+ SchedulingData = System.Scheduler.SchedulingData;
- MutexWaiters = new List<KThread>();
+ SiblingsPerCore = new LinkedListNode<KThread>[KScheduler.CpuCoresCount];
- CoreMask = 1 << ProcessorId;
+ MutexWaiters = new LinkedList<KThread>();
- ActualPriority = WantedPriority = Priority;
+ AffinityMask = 1 << ProcessorId;
+
+ DynamicPriority = BasePriority = Priority;
+
+ CurrentCore = PreferredCore;
+ }
+
+ public long Start()
+ {
+ long Result = MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating);
+
+ System.CriticalSectionLock.Lock();
+
+ if (!ShallBeTerminated)
+ {
+ KThread CurrentThread = System.Scheduler.GetCurrentThread();
+
+ while (SchedFlags != ThreadSchedState.TerminationPending &&
+ CurrentThread.SchedFlags != ThreadSchedState.TerminationPending &&
+ !CurrentThread.ShallBeTerminated)
+ {
+ if ((SchedFlags & ThreadSchedState.LowNibbleMask) != ThreadSchedState.None)
+ {
+ Result = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
+
+ break;
+ }
+
+ if (CurrentThread.ForcePauseFlags == ThreadSchedState.None)
+ {
+ if (Owner != null && ForcePauseFlags != ThreadSchedState.None)
+ {
+ CombineForcePauseFlags();
+ }
+
+ SetNewSchedFlags(ThreadSchedState.Running);
+
+ Result = 0;
+
+ break;
+ }
+ else
+ {
+ CurrentThread.CombineForcePauseFlags();
+
+ System.CriticalSectionLock.Unlock();
+ System.CriticalSectionLock.Lock();
+
+ if (CurrentThread.ShallBeTerminated)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ System.CriticalSectionLock.Unlock();
+
+ return Result;
+ }
+
+ public void Exit()
+ {
+ System.CriticalSectionLock.Lock();
+
+ ForcePauseFlags &= ~ThreadSchedState.ExceptionalMask;
+
+ ExitImpl();
+
+ System.CriticalSectionLock.Unlock();
+ }
+
+ private void ExitImpl()
+ {
+ System.CriticalSectionLock.Lock();
+
+ SetNewSchedFlags(ThreadSchedState.TerminationPending);
+
+ HasExited = true;
+
+ Signal();
+
+ System.CriticalSectionLock.Unlock();
+ }
+
+ public long Sleep(long Timeout)
+ {
+ System.CriticalSectionLock.Lock();
+
+ if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
+ {
+ System.CriticalSectionLock.Unlock();
+
+ return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating);
+ }
+
+ SetNewSchedFlags(ThreadSchedState.Paused);
+
+ if (Timeout > 0)
+ {
+ System.TimeManager.ScheduleFutureInvocation(this, Timeout);
+ }
+
+ System.CriticalSectionLock.Unlock();
+
+ if (Timeout > 0)
+ {
+ System.TimeManager.UnscheduleFutureInvocation(this);
+ }
+
+ return 0;
+ }
+
+ public void Yield()
+ {
+ System.CriticalSectionLock.Lock();
+
+ if (SchedFlags != ThreadSchedState.Running)
+ {
+ System.CriticalSectionLock.Unlock();
+
+ System.Scheduler.ContextSwitch();
+
+ return;
+ }
+
+ if (DynamicPriority < KScheduler.PrioritiesCount)
+ {
+ //Move current thread to the end of the queue.
+ SchedulingData.Reschedule(DynamicPriority, CurrentCore, this);
+ }
+
+ Scheduler.ThreadReselectionRequested = true;
+
+ System.CriticalSectionLock.Unlock();
+
+ System.Scheduler.ContextSwitch();
+ }
+
+ public void YieldWithLoadBalancing()
+ {
+ int Prio = DynamicPriority;
+ int Core = CurrentCore;
+
+ System.CriticalSectionLock.Lock();
+
+ if (SchedFlags != ThreadSchedState.Running)
+ {
+ System.CriticalSectionLock.Unlock();
+
+ System.Scheduler.ContextSwitch();
+
+ return;
+ }
+
+ 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.LastScheduledTicks >= Thread.LastScheduledTicks ||
+ NextThreadOnCurrentQueue.DynamicPriority < Thread.DynamicPriority)
+ {
+ yield return Thread;
+ }
+ }
+ }
+
+ KThread Dst = SuitableCandidates().FirstOrDefault(x => x.DynamicPriority <= Prio);
+
+ if (Dst != null)
+ {
+ SchedulingData.TransferToCore(Dst.DynamicPriority, Core, Dst);
+
+ Scheduler.ThreadReselectionRequested = true;
+ }
+
+ if (this != NextThreadOnCurrentQueue)
+ {
+ Scheduler.ThreadReselectionRequested = true;
+ }
+
+ System.CriticalSectionLock.Unlock();
+
+ System.Scheduler.ContextSwitch();
+ }
+
+ public void YieldAndWaitForLoadBalancing()
+ {
+ System.CriticalSectionLock.Lock();
+
+ if (SchedFlags != ThreadSchedState.Running)
+ {
+ System.CriticalSectionLock.Unlock();
+
+ System.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)
+ {
+ Scheduler.ThreadReselectionRequested = true;
+ }
+
+ System.CriticalSectionLock.Unlock();
+
+ System.Scheduler.ContextSwitch();
}
public void SetPriority(int Priority)
{
- WantedPriority = Priority;
+ System.CriticalSectionLock.Lock();
- UpdatePriority();
+ BasePriority = Priority;
+
+ UpdatePriorityInheritance();
+
+ System.CriticalSectionLock.Unlock();
}
- public void UpdatePriority()
+ public long SetActivity(bool Pause)
{
- bool PriorityChanged;
+ long Result = 0;
+
+ System.CriticalSectionLock.Lock();
+
+ ThreadSchedState LowNibble = SchedFlags & ThreadSchedState.LowNibbleMask;
- lock (Process.ThreadSyncLock)
+ if (LowNibble != ThreadSchedState.Paused && LowNibble != ThreadSchedState.Running)
{
- int OldPriority = ActualPriority;
+ System.CriticalSectionLock.Unlock();
- int CurrPriority = WantedPriority;
+ return MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
+ }
+
+ System.CriticalSectionLock.Lock();
- foreach (KThread Thread in MutexWaiters)
+ if (!ShallBeTerminated && SchedFlags != ThreadSchedState.TerminationPending)
+ {
+ if (Pause)
+ {
+ //Pause, the force pause flag should be clear (thread is NOT paused).
+ if ((ForcePauseFlags & ThreadSchedState.ForcePauseFlag) == 0)
+ {
+ ForcePauseFlags |= ThreadSchedState.ForcePauseFlag;
+
+ CombineForcePauseFlags();
+ }
+ else
+ {
+ Result = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
+ }
+ }
+ else
{
- int WantedPriority = Thread.WantedPriority;
+ //Unpause, the force pause flag should be set (thread is paused).
+ if ((ForcePauseFlags & ThreadSchedState.ForcePauseFlag) != 0)
+ {
+ ThreadSchedState OldForcePauseFlags = ForcePauseFlags;
+
+ ForcePauseFlags &= ~ThreadSchedState.ForcePauseFlag;
+
+ if ((OldForcePauseFlags & ~ThreadSchedState.ForcePauseFlag) == ThreadSchedState.None)
+ {
+ ThreadSchedState OldSchedFlags = SchedFlags;
- if (CurrPriority > WantedPriority)
+ SchedFlags &= ThreadSchedState.LowNibbleMask;
+
+ AdjustScheduling(OldSchedFlags);
+ }
+ }
+ else
{
- CurrPriority = WantedPriority;
+ Result = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
}
}
+ }
+
+ System.CriticalSectionLock.Unlock();
+ System.CriticalSectionLock.Unlock();
+
+ return Result;
+ }
+
+ public void CancelSynchronization()
+ {
+ System.CriticalSectionLock.Lock();
+
+ if ((SchedFlags & ThreadSchedState.LowNibbleMask) != ThreadSchedState.Paused || !WaitingSync)
+ {
+ SyncCancelled = true;
+ }
+ else if (WithholderNode != null)
+ {
+ System.Withholders.Remove(WithholderNode);
+
+ SetNewSchedFlags(ThreadSchedState.Running);
- PriorityChanged = CurrPriority != OldPriority;
+ WithholderNode = null;
- ActualPriority = CurrPriority;
+ SyncCancelled = true;
}
+ else
+ {
+ SignaledObj = null;
+ ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Cancelled);
+
+ SetNewSchedFlags(ThreadSchedState.Running);
+
+ SyncCancelled = false;
+ }
+
+ System.CriticalSectionLock.Unlock();
+ }
+
+ public long SetCoreAndAffinityMask(int NewCore, long NewAffinityMask)
+ {
+ System.CriticalSectionLock.Lock();
+
+ bool UseOverride = AffinityOverrideCount != 0;
- if (PriorityChanged)
+ //The value -3 is "do not change the preferred core".
+ if (NewCore == -3)
{
- Process.Scheduler.Resort(this);
+ NewCore = UseOverride ? PreferredCoreOverride : PreferredCore;
- MutexOwner?.UpdatePriority();
+ if ((NewAffinityMask & (1 << NewCore)) == 0)
+ {
+ System.CriticalSectionLock.Unlock();
+
+ return MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
+ }
}
+
+ if (UseOverride)
+ {
+ PreferredCoreOverride = NewCore;
+ AffinityMaskOverride = NewAffinityMask;
+ }
+ else
+ {
+ long OldAffinityMask = AffinityMask;
+
+ PreferredCore = NewCore;
+ AffinityMask = NewAffinityMask;
+
+ if (OldAffinityMask != NewAffinityMask)
+ {
+ int OldCore = CurrentCore;
+
+ if (CurrentCore >= 0 && ((AffinityMask >> CurrentCore) & 1) == 0)
+ {
+ if (PreferredCore < 0)
+ {
+ CurrentCore = HighestSetCore(AffinityMask);
+ }
+ else
+ {
+ CurrentCore = PreferredCore;
+ }
+ }
+
+ AdjustSchedulingForNewAffinity(OldAffinityMask, OldCore);
+ }
+ }
+
+ System.CriticalSectionLock.Unlock();
+
+ return 0;
+ }
+
+ 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;
+ ThreadSchedState LowNibble = SchedFlags & ThreadSchedState.LowNibbleMask;
+
+ SchedFlags = LowNibble | ForcePauseFlags;
+
+ AdjustScheduling(OldFlags);
+ }
+
+ private void SetNewSchedFlags(ThreadSchedState NewFlags)
+ {
+ System.CriticalSectionLock.Lock();
+
+ ThreadSchedState OldFlags = SchedFlags;
+
+ SchedFlags = (OldFlags & ThreadSchedState.HighNibbleMask) | NewFlags;
+
+ if ((OldFlags & ThreadSchedState.LowNibbleMask) != NewFlags)
+ {
+ AdjustScheduling(OldFlags);
+ }
+
+ System.CriticalSectionLock.Unlock();
+ }
+
+ public void ReleaseAndResume()
+ {
+ System.CriticalSectionLock.Lock();
+
+ if ((SchedFlags & ThreadSchedState.LowNibbleMask) == ThreadSchedState.Paused)
+ {
+ if (WithholderNode != null)
+ {
+ System.Withholders.Remove(WithholderNode);
+
+ SetNewSchedFlags(ThreadSchedState.Running);
+
+ WithholderNode = null;
+ }
+ else
+ {
+ SetNewSchedFlags(ThreadSchedState.Running);
+ }
+ }
+
+ System.CriticalSectionLock.Unlock();
+ }
+
+ public void Reschedule(ThreadSchedState NewFlags)
+ {
+ System.CriticalSectionLock.Lock();
+
+ ThreadSchedState OldFlags = SchedFlags;
+
+ SchedFlags = (OldFlags & ThreadSchedState.HighNibbleMask) |
+ (NewFlags & ThreadSchedState.LowNibbleMask);
+
+ AdjustScheduling(OldFlags);
+
+ System.CriticalSectionLock.Unlock();
+ }
+
+ public void AddMutexWaiter(KThread Requester)
+ {
+ AddToMutexWaitersList(Requester);
+
+ Requester.MutexOwner = this;
+
+ UpdatePriorityInheritance();
+ }
+
+ public void RemoveMutexWaiter(KThread Thread)
+ {
+ if (Thread.MutexWaiterNode?.List != null)
+ {
+ MutexWaiters.Remove(Thread.MutexWaiterNode);
+ }
+
+ Thread.MutexOwner = null;
+
+ UpdatePriorityInheritance();
+ }
+
+ public KThread RelinquishMutex(long MutexAddress, out int Count)
+ {
+ Count = 0;
+
+ if (MutexWaiters.First == null)
+ {
+ return null;
+ }
+
+ KThread NewMutexOwner = null;
+
+ LinkedListNode<KThread> CurrentNode = MutexWaiters.First;
+
+ do
+ {
+ //Skip all threads that are not waiting for this mutex.
+ while (CurrentNode != null && CurrentNode.Value.MutexAddress != MutexAddress)
+ {
+ CurrentNode = CurrentNode.Next;
+ }
+
+ if (CurrentNode == null)
+ {
+ break;
+ }
+
+ LinkedListNode<KThread> NextNode = CurrentNode.Next;
+
+ MutexWaiters.Remove(CurrentNode);
+
+ CurrentNode.Value.MutexOwner = NewMutexOwner;
+
+ if (NewMutexOwner != null)
+ {
+ //New owner was already selected, re-insert on new owner list.
+ NewMutexOwner.AddToMutexWaitersList(CurrentNode.Value);
+ }
+ else
+ {
+ //New owner not selected yet, use current thread.
+ NewMutexOwner = CurrentNode.Value;
+ }
+
+ Count++;
+
+ CurrentNode = NextNode;
+ }
+ while (CurrentNode != null);
+
+ if (NewMutexOwner != null)
+ {
+ UpdatePriorityInheritance();
+
+ NewMutexOwner.UpdatePriorityInheritance();
+ }
+
+ return NewMutexOwner;
+ }
+
+ private void UpdatePriorityInheritance()
+ {
+ //If any of the threads waiting for the mutex has
+ //higher priority than the current thread, then
+ //the current thread inherits that priority.
+ int HighestPriority = BasePriority;
+
+ if (MutexWaiters.First != null)
+ {
+ int WaitingDynamicPriority = MutexWaiters.First.Value.DynamicPriority;
+
+ if (WaitingDynamicPriority < HighestPriority)
+ {
+ HighestPriority = WaitingDynamicPriority;
+ }
+ }
+
+ if (HighestPriority != DynamicPriority)
+ {
+ int OldPriority = DynamicPriority;
+
+ DynamicPriority = HighestPriority;
+
+ AdjustSchedulingForNewPriority(OldPriority);
+
+ if (MutexOwner != null)
+ {
+ //Remove and re-insert to ensure proper sorting based on new priority.
+ MutexOwner.MutexWaiters.Remove(MutexWaiterNode);
+
+ MutexOwner.AddToMutexWaitersList(this);
+
+ MutexOwner.UpdatePriorityInheritance();
+ }
+ }
+ }
+
+ private void AddToMutexWaitersList(KThread Thread)
+ {
+ LinkedListNode<KThread> NextPrio = MutexWaiters.First;
+
+ int CurrentPriority = Thread.DynamicPriority;
+
+ while (NextPrio != null && NextPrio.Value.DynamicPriority <= CurrentPriority)
+ {
+ NextPrio = NextPrio.Next;
+ }
+
+ if (NextPrio != null)
+ {
+ Thread.MutexWaiterNode = MutexWaiters.AddBefore(NextPrio, Thread);
+ }
+ else
+ {
+ Thread.MutexWaiterNode = MutexWaiters.AddLast(Thread);
+ }
+ }
+
+ private void AdjustScheduling(ThreadSchedState OldFlags)
+ {
+ if (OldFlags == SchedFlags)
+ {
+ return;
+ }
+
+ if (OldFlags == ThreadSchedState.Running)
+ {
+ //Was running, now it's stopped.
+ if (CurrentCore >= 0)
+ {
+ SchedulingData.Unschedule(DynamicPriority, CurrentCore, this);
+ }
+
+ for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
+ {
+ if (Core != CurrentCore && ((AffinityMask >> Core) & 1) != 0)
+ {
+ SchedulingData.Unsuggest(DynamicPriority, Core, this);
+ }
+ }
+ }
+ else if (SchedFlags == ThreadSchedState.Running)
+ {
+ //Was stopped, now it's running.
+ if (CurrentCore >= 0)
+ {
+ SchedulingData.Schedule(DynamicPriority, CurrentCore, this);
+ }
+
+ for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
+ {
+ if (Core != CurrentCore && ((AffinityMask >> Core) & 1) != 0)
+ {
+ SchedulingData.Suggest(DynamicPriority, Core, this);
+ }
+ }
+ }
+
+ Scheduler.ThreadReselectionRequested = true;
+ }
+
+ private void AdjustSchedulingForNewPriority(int OldPriority)
+ {
+ if (SchedFlags != ThreadSchedState.Running)
+ {
+ return;
+ }
+
+ //Remove thread from the old priority queues.
+ if (CurrentCore >= 0)
+ {
+ SchedulingData.Unschedule(OldPriority, CurrentCore, this);
+ }
+
+ for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
+ {
+ if (Core != CurrentCore && ((AffinityMask >> Core) & 1) != 0)
+ {
+ SchedulingData.Unsuggest(OldPriority, Core, this);
+ }
+ }
+
+ //Add thread to the new priority queues.
+ KThread CurrentThread = Scheduler.GetCurrentThread();
+
+ if (CurrentCore >= 0)
+ {
+ if (CurrentThread == this)
+ {
+ SchedulingData.SchedulePrepend(DynamicPriority, CurrentCore, this);
+ }
+ else
+ {
+ SchedulingData.Schedule(DynamicPriority, CurrentCore, this);
+ }
+ }
+
+ for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
+ {
+ if (Core != CurrentCore && ((AffinityMask >> Core) & 1) != 0)
+ {
+ SchedulingData.Suggest(DynamicPriority, Core, this);
+ }
+ }
+
+ Scheduler.ThreadReselectionRequested = true;
+ }
+
+ private void AdjustSchedulingForNewAffinity(long OldAffinityMask, int OldCore)
+ {
+ if (SchedFlags != ThreadSchedState.Running || DynamicPriority >= KScheduler.PrioritiesCount)
+ {
+ return;
+ }
+
+ //Remove from old queues.
+ for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
+ {
+ if (((OldAffinityMask >> Core) & 1) != 0)
+ {
+ if (Core == OldCore)
+ {
+ SchedulingData.Unschedule(DynamicPriority, Core, this);
+ }
+ else
+ {
+ SchedulingData.Unsuggest(DynamicPriority, Core, this);
+ }
+ }
+ }
+
+ //Insert on new queues.
+ for (int Core = 0; Core < KScheduler.CpuCoresCount; Core++)
+ {
+ if (((AffinityMask >> Core) & 1) != 0)
+ {
+ if (Core == CurrentCore)
+ {
+ SchedulingData.Schedule(DynamicPriority, Core, this);
+ }
+ else
+ {
+ SchedulingData.Suggest(DynamicPriority, Core, this);
+ }
+ }
+ }
+
+ Scheduler.ThreadReselectionRequested = true;
+ }
+
+ public override bool IsSignaled()
+ {
+ return HasExited;
+ }
+
+ public void ClearExclusive()
+ {
+ Owner.Memory.ClearExclusive(CurrentCore);
+ }
+
+ public void TimeUp()
+ {
+ System.CriticalSectionLock.Lock();
+
+ SetNewSchedFlags(ThreadSchedState.Running);
+
+ System.CriticalSectionLock.Unlock();
}
}
} \ No newline at end of file