From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001 From: TSR Berry <20988865+TSRBerry@users.noreply.github.com> Date: Sat, 8 Apr 2023 01:22:00 +0200 Subject: Move solution and projects to src --- .../HOS/Kernel/Threading/KSynchronization.cs | 142 +++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs (limited to 'src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs') diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs new file mode 100644 index 00000000..9c196810 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs @@ -0,0 +1,142 @@ +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.Horizon.Common; +using System; +using System.Buffers; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Kernel.Threading +{ + class KSynchronization + { + private KernelContext _context; + + public KSynchronization(KernelContext context) + { + _context = context; + } + + public Result WaitFor(Span syncObjs, long timeout, out int handleIndex) + { + handleIndex = 0; + + Result result = KernelResult.TimedOut; + + _context.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; + + _context.CriticalSection.Leave(); + + return Result.Success; + } + + if (timeout == 0) + { + _context.CriticalSection.Leave(); + + return result; + } + + KThread currentThread = KernelStatic.GetCurrentThread(); + + if (currentThread.TerminationRequested) + { + result = KernelResult.ThreadTerminating; + } + else if (currentThread.SyncCancelled) + { + currentThread.SyncCancelled = false; + + result = KernelResult.Cancelled; + } + else + { + LinkedListNode[] syncNodesArray = ArrayPool>.Shared.Rent(syncObjs.Length); + + Span> syncNodes = syncNodesArray.AsSpan(0, 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) + { + _context.TimeManager.ScheduleFutureInvocation(currentThread, timeout); + } + + _context.CriticalSection.Leave(); + + currentThread.WaitingSync = false; + + if (timeout > 0) + { + _context.TimeManager.UnscheduleFutureInvocation(currentThread); + } + + _context.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; + } + } + + ArrayPool>.Shared.Return(syncNodesArray); + } + + _context.CriticalSection.Leave(); + + return result; + } + + public void SignalObject(KSynchronizationObject syncObj) + { + _context.CriticalSection.Enter(); + + if (syncObj.IsSignaled()) + { + LinkedListNode node = syncObj.WaitingThreads.First; + + while (node != null) + { + KThread thread = node.Value; + + if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused) + { + thread.SignaledObj = syncObj; + thread.ObjSyncResult = Result.Success; + + thread.Reschedule(ThreadSchedState.Running); + } + + node = node.Next; + } + } + + _context.CriticalSection.Leave(); + } + } +} \ No newline at end of file -- cgit v1.2.3