diff options
author | gdkchan <gab.dark.100@gmail.com> | 2018-12-18 03:33:36 -0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-18 03:33:36 -0200 |
commit | 0039bb639493b2d1e2764cae380311ba8e87704b (patch) | |
tree | 63a912a95c8261775c2acb8a5b9ca0f10ad4ae33 /Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs | |
parent | 2534a7f10c627810e6e0272b4cc9758e90f733c1 (diff) |
Refactor SVC handler (#540)
* Refactor SVC handler
* Get rid of KernelErr
* Split kernel code files into multiple folders
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs')
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs new file mode 100644 index 00000000..450155ce --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs @@ -0,0 +1,136 @@ +using Ryujinx.HLE.HOS.Kernel.Common; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Kernel.Threading +{ + class KSynchronization + { + private Horizon _system; + + public KSynchronization(Horizon system) + { + _system = system; + } + + public KernelResult WaitFor(KSynchronizationObject[] syncObjs, long timeout, out int handleIndex) + { + handleIndex = 0; + + KernelResult result = KernelResult.TimedOut; + + _system.CriticalSection.Enter(); + + //Check if objects are already signaled before waiting. + for (int index = 0; index < syncObjs.Length; index++) + { + if (!syncObjs[index].IsSignaled()) + { + continue; + } + + handleIndex = index; + + _system.CriticalSection.Leave(); + + return 0; + } + + if (timeout == 0) + { + _system.CriticalSection.Leave(); + + return result; + } + + KThread currentThread = _system.Scheduler.GetCurrentThread(); + + if (currentThread.ShallBeTerminated || + currentThread.SchedFlags == ThreadSchedState.TerminationPending) + { + result = KernelResult.ThreadTerminating; + } + else if (currentThread.SyncCancelled) + { + currentThread.SyncCancelled = false; + + result = KernelResult.Cancelled; + } + else + { + LinkedListNode<KThread>[] syncNodes = new LinkedListNode<KThread>[syncObjs.Length]; + + for (int index = 0; index < syncObjs.Length; index++) + { + syncNodes[index] = syncObjs[index].AddWaitingThread(currentThread); + } + + currentThread.WaitingSync = true; + currentThread.SignaledObj = null; + currentThread.ObjSyncResult = result; + + currentThread.Reschedule(ThreadSchedState.Paused); + + if (timeout > 0) + { + _system.TimeManager.ScheduleFutureInvocation(currentThread, timeout); + } + + _system.CriticalSection.Leave(); + + currentThread.WaitingSync = false; + + if (timeout > 0) + { + _system.TimeManager.UnscheduleFutureInvocation(currentThread); + } + + _system.CriticalSection.Enter(); + + result = currentThread.ObjSyncResult; + + handleIndex = -1; + + for (int index = 0; index < syncObjs.Length; index++) + { + syncObjs[index].RemoveWaitingThread(syncNodes[index]); + + if (syncObjs[index] == currentThread.SignaledObj) + { + handleIndex = index; + } + } + } + + _system.CriticalSection.Leave(); + + return result; + } + + public void SignalObject(KSynchronizationObject syncObj) + { + _system.CriticalSection.Enter(); + + if (syncObj.IsSignaled()) + { + LinkedListNode<KThread> node = syncObj.WaitingThreads.First; + + while (node != null) + { + KThread thread = node.Value; + + if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused) + { + thread.SignaledObj = syncObj; + thread.ObjSyncResult = KernelResult.Success; + + thread.Reschedule(ThreadSchedState.Running); + } + + node = node.Next; + } + } + + _system.CriticalSection.Leave(); + } + } +}
\ No newline at end of file |