From 0039bb639493b2d1e2764cae380311ba8e87704b Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 18 Dec 2018 03:33:36 -0200 Subject: Refactor SVC handler (#540) * Refactor SVC handler * Get rid of KernelErr * Split kernel code files into multiple folders --- .../HOS/Kernel/Threading/KSchedulingData.cs | 207 +++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 Ryujinx.HLE/HOS/Kernel/Threading/KSchedulingData.cs (limited to 'Ryujinx.HLE/HOS/Kernel/Threading/KSchedulingData.cs') diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KSchedulingData.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KSchedulingData.cs new file mode 100644 index 00000000..83c4a079 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KSchedulingData.cs @@ -0,0 +1,207 @@ +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Kernel.Threading +{ + class KSchedulingData + { + private LinkedList[][] _scheduledThreadsPerPrioPerCore; + private LinkedList[][] _suggestedThreadsPerPrioPerCore; + + private long[] _scheduledPrioritiesPerCore; + private long[] _suggestedPrioritiesPerCore; + + public KSchedulingData() + { + _suggestedThreadsPerPrioPerCore = new LinkedList[KScheduler.PrioritiesCount][]; + _scheduledThreadsPerPrioPerCore = new LinkedList[KScheduler.PrioritiesCount][]; + + for (int prio = 0; prio < KScheduler.PrioritiesCount; prio++) + { + _suggestedThreadsPerPrioPerCore[prio] = new LinkedList[KScheduler.CpuCoresCount]; + _scheduledThreadsPerPrioPerCore[prio] = new LinkedList[KScheduler.CpuCoresCount]; + + for (int core = 0; core < KScheduler.CpuCoresCount; core++) + { + _suggestedThreadsPerPrioPerCore[prio][core] = new LinkedList(); + _scheduledThreadsPerPrioPerCore[prio][core] = new LinkedList(); + } + } + + _scheduledPrioritiesPerCore = new long[KScheduler.CpuCoresCount]; + _suggestedPrioritiesPerCore = new long[KScheduler.CpuCoresCount]; + } + + public IEnumerable SuggestedThreads(int core) + { + return Iterate(_suggestedThreadsPerPrioPerCore, _suggestedPrioritiesPerCore, core); + } + + public IEnumerable ScheduledThreads(int core) + { + return Iterate(_scheduledThreadsPerPrioPerCore, _scheduledPrioritiesPerCore, core); + } + + private IEnumerable Iterate(LinkedList[][] listPerPrioPerCore, long[] prios, int core) + { + long prioMask = prios[core]; + + int prio = CountTrailingZeros(prioMask); + + prioMask &= ~(1L << prio); + + while (prio < KScheduler.PrioritiesCount) + { + LinkedList list = listPerPrioPerCore[prio][core]; + + LinkedListNode node = list.First; + + while (node != null) + { + yield return node.Value; + + node = node.Next; + } + + prio = CountTrailingZeros(prioMask); + + prioMask &= ~(1L << prio); + } + } + + private int CountTrailingZeros(long value) + { + int count = 0; + + while (((value >> count) & 0xf) == 0 && count < 64) + { + count += 4; + } + + while (((value >> count) & 1) == 0 && count < 64) + { + count++; + } + + return count; + } + + public void TransferToCore(int prio, int dstCore, KThread thread) + { + bool schedulable = thread.DynamicPriority < KScheduler.PrioritiesCount; + + int srcCore = thread.CurrentCore; + + thread.CurrentCore = dstCore; + + if (srcCore == dstCore || !schedulable) + { + return; + } + + if (srcCore >= 0) + { + Unschedule(prio, srcCore, thread); + } + + if (dstCore >= 0) + { + Unsuggest(prio, dstCore, thread); + Schedule(prio, dstCore, thread); + } + + if (srcCore >= 0) + { + Suggest(prio, srcCore, thread); + } + } + + public void Suggest(int prio, int core, KThread thread) + { + if (prio >= KScheduler.PrioritiesCount) + { + return; + } + + thread.SiblingsPerCore[core] = SuggestedQueue(prio, core).AddFirst(thread); + + _suggestedPrioritiesPerCore[core] |= 1L << prio; + } + + public void Unsuggest(int prio, int core, KThread thread) + { + if (prio >= KScheduler.PrioritiesCount) + { + return; + } + + LinkedList queue = SuggestedQueue(prio, core); + + queue.Remove(thread.SiblingsPerCore[core]); + + if (queue.First == null) + { + _suggestedPrioritiesPerCore[core] &= ~(1L << prio); + } + } + + public void Schedule(int prio, int core, KThread thread) + { + if (prio >= KScheduler.PrioritiesCount) + { + return; + } + + thread.SiblingsPerCore[core] = ScheduledQueue(prio, core).AddLast(thread); + + _scheduledPrioritiesPerCore[core] |= 1L << prio; + } + + public void SchedulePrepend(int prio, int core, KThread thread) + { + if (prio >= KScheduler.PrioritiesCount) + { + return; + } + + thread.SiblingsPerCore[core] = ScheduledQueue(prio, core).AddFirst(thread); + + _scheduledPrioritiesPerCore[core] |= 1L << prio; + } + + public void Reschedule(int prio, int core, KThread thread) + { + LinkedList queue = ScheduledQueue(prio, core); + + queue.Remove(thread.SiblingsPerCore[core]); + + thread.SiblingsPerCore[core] = queue.AddLast(thread); + } + + public void Unschedule(int prio, int core, KThread thread) + { + if (prio >= KScheduler.PrioritiesCount) + { + return; + } + + LinkedList queue = ScheduledQueue(prio, core); + + queue.Remove(thread.SiblingsPerCore[core]); + + if (queue.First == null) + { + _scheduledPrioritiesPerCore[core] &= ~(1L << prio); + } + } + + private LinkedList SuggestedQueue(int prio, int core) + { + return _suggestedThreadsPerPrioPerCore[prio][core]; + } + + private LinkedList ScheduledQueue(int prio, int core) + { + return _scheduledThreadsPerPrioPerCore[prio][core]; + } + } +} \ No newline at end of file -- cgit v1.2.3