From b8133c19971c7a2026af803003fafedbdb70488e Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 18 Sep 2018 20:36:43 -0300 Subject: 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 --- Ryujinx.HLE/HOS/Kernel/KSynchronization.cs | 135 +++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 Ryujinx.HLE/HOS/Kernel/KSynchronization.cs (limited to 'Ryujinx.HLE/HOS/Kernel/KSynchronization.cs') diff --git a/Ryujinx.HLE/HOS/Kernel/KSynchronization.cs b/Ryujinx.HLE/HOS/Kernel/KSynchronization.cs new file mode 100644 index 00000000..57a6296c --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KSynchronization.cs @@ -0,0 +1,135 @@ +using System.Collections.Generic; + +using static Ryujinx.HLE.HOS.ErrorCode; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KSynchronization + { + private Horizon System; + + public KSynchronization(Horizon System) + { + this.System = System; + } + + public long WaitFor(KSynchronizationObject[] SyncObjs, long Timeout, ref int HndIndex) + { + long Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); + + System.CriticalSectionLock.Lock(); + + //Check if objects are already signaled before waiting. + for (int Index = 0; Index < SyncObjs.Length; Index++) + { + if (!SyncObjs[Index].IsSignaled()) + { + continue; + } + + HndIndex = Index; + + System.CriticalSectionLock.Unlock(); + + return 0; + } + + if (Timeout == 0) + { + System.CriticalSectionLock.Unlock(); + + return Result; + } + + KThread CurrentThread = System.Scheduler.GetCurrentThread(); + + if (CurrentThread.ShallBeTerminated || + CurrentThread.SchedFlags == ThreadSchedState.TerminationPending) + { + Result = MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); + } + else if (CurrentThread.SyncCancelled) + { + CurrentThread.SyncCancelled = false; + + Result = MakeError(ErrorModule.Kernel, KernelErr.Cancelled); + } + else + { + LinkedListNode[] SyncNodes = new LinkedListNode[SyncObjs.Length]; + + for (int Index = 0; Index < SyncObjs.Length; Index++) + { + SyncNodes[Index] = SyncObjs[Index].AddWaitingThread(CurrentThread); + } + + CurrentThread.WaitingSync = true; + CurrentThread.SignaledObj = null; + CurrentThread.ObjSyncResult = (int)Result; + + CurrentThread.Reschedule(ThreadSchedState.Paused); + + if (Timeout > 0) + { + System.TimeManager.ScheduleFutureInvocation(CurrentThread, Timeout); + } + + System.CriticalSectionLock.Unlock(); + + CurrentThread.WaitingSync = false; + + if (Timeout > 0) + { + System.TimeManager.UnscheduleFutureInvocation(CurrentThread); + } + + System.CriticalSectionLock.Lock(); + + Result = (uint)CurrentThread.ObjSyncResult; + + HndIndex = -1; + + for (int Index = 0; Index < SyncObjs.Length; Index++) + { + SyncObjs[Index].RemoveWaitingThread(SyncNodes[Index]); + + if (SyncObjs[Index] == CurrentThread.SignaledObj) + { + HndIndex = Index; + } + } + } + + System.CriticalSectionLock.Unlock(); + + return Result; + } + + public void SignalObject(KSynchronizationObject SyncObj) + { + System.CriticalSectionLock.Lock(); + + if (SyncObj.IsSignaled()) + { + LinkedListNode Node = SyncObj.WaitingThreads.First; + + while (Node != null) + { + KThread Thread = Node.Value; + + if ((Thread.SchedFlags & ThreadSchedState.LowNibbleMask) == ThreadSchedState.Paused) + { + Thread.SignaledObj = SyncObj; + Thread.ObjSyncResult = 0; + + Thread.Reschedule(ThreadSchedState.Running); + } + + Node = Node.Next; + } + } + + System.CriticalSectionLock.Unlock(); + } + } +} \ No newline at end of file -- cgit v1.2.3