diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs')
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs | 581 |
1 files changed, 0 insertions, 581 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs deleted file mode 100644 index 74867b44..00000000 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs +++ /dev/null @@ -1,581 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Process; -using Ryujinx.Horizon.Common; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -namespace Ryujinx.HLE.HOS.Kernel.Threading -{ - class KAddressArbiter - { - private const int HasListenersMask = 0x40000000; - - private readonly KernelContext _context; - - private readonly List<KThread> _condVarThreads; - private readonly List<KThread> _arbiterThreads; - - public KAddressArbiter(KernelContext context) - { - _context = context; - - _condVarThreads = new List<KThread>(); - _arbiterThreads = new List<KThread>(); - } - - public Result ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle) - { - KThread currentThread = KernelStatic.GetCurrentThread(); - - _context.CriticalSection.Enter(); - - if (currentThread.TerminationRequested) - { - _context.CriticalSection.Leave(); - - return KernelResult.ThreadTerminating; - } - - currentThread.SignaledObj = null; - currentThread.ObjSyncResult = Result.Success; - - KProcess currentProcess = KernelStatic.GetCurrentProcess(); - - if (!KernelTransfer.UserToKernel(out int mutexValue, mutexAddress)) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidMemState; - } - - if (mutexValue != (ownerHandle | HasListenersMask)) - { - _context.CriticalSection.Leave(); - - return Result.Success; - } - - KThread mutexOwner = currentProcess.HandleTable.GetObject<KThread>(ownerHandle); - - if (mutexOwner == null) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidHandle; - } - - currentThread.MutexAddress = mutexAddress; - currentThread.ThreadHandleForUserMutex = requesterHandle; - - mutexOwner.AddMutexWaiter(currentThread); - - currentThread.Reschedule(ThreadSchedState.Paused); - - _context.CriticalSection.Leave(); - _context.CriticalSection.Enter(); - - if (currentThread.MutexOwner != null) - { - currentThread.MutexOwner.RemoveMutexWaiter(currentThread); - } - - _context.CriticalSection.Leave(); - - return currentThread.ObjSyncResult; - } - - public Result ArbitrateUnlock(ulong mutexAddress) - { - _context.CriticalSection.Enter(); - - KThread currentThread = KernelStatic.GetCurrentThread(); - - (int mutexValue, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress); - - Result result = Result.Success; - - if (!KernelTransfer.KernelToUser(mutexAddress, mutexValue)) - { - result = KernelResult.InvalidMemState; - } - - if (result != Result.Success && newOwnerThread != null) - { - newOwnerThread.SignaledObj = null; - newOwnerThread.ObjSyncResult = result; - } - - _context.CriticalSection.Leave(); - - return result; - } - - public Result WaitProcessWideKeyAtomic(ulong mutexAddress, ulong condVarAddress, int threadHandle, long timeout) - { - _context.CriticalSection.Enter(); - - KThread currentThread = KernelStatic.GetCurrentThread(); - - currentThread.SignaledObj = null; - currentThread.ObjSyncResult = KernelResult.TimedOut; - - if (currentThread.TerminationRequested) - { - _context.CriticalSection.Leave(); - - return KernelResult.ThreadTerminating; - } - - (int mutexValue, _) = MutexUnlock(currentThread, mutexAddress); - - KernelTransfer.KernelToUser(condVarAddress, 1); - - if (!KernelTransfer.KernelToUser(mutexAddress, mutexValue)) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidMemState; - } - - currentThread.MutexAddress = mutexAddress; - currentThread.ThreadHandleForUserMutex = threadHandle; - currentThread.CondVarAddress = condVarAddress; - - _condVarThreads.Add(currentThread); - - if (timeout != 0) - { - currentThread.Reschedule(ThreadSchedState.Paused); - - if (timeout > 0) - { - _context.TimeManager.ScheduleFutureInvocation(currentThread, timeout); - } - } - - _context.CriticalSection.Leave(); - - if (timeout > 0) - { - _context.TimeManager.UnscheduleFutureInvocation(currentThread); - } - - _context.CriticalSection.Enter(); - - if (currentThread.MutexOwner != null) - { - currentThread.MutexOwner.RemoveMutexWaiter(currentThread); - } - - _condVarThreads.Remove(currentThread); - - _context.CriticalSection.Leave(); - - return currentThread.ObjSyncResult; - } - - private (int, KThread) MutexUnlock(KThread currentThread, ulong mutexAddress) - { - KThread newOwnerThread = currentThread.RelinquishMutex(mutexAddress, out int count); - - int mutexValue = 0; - - if (newOwnerThread != null) - { - mutexValue = newOwnerThread.ThreadHandleForUserMutex; - - if (count >= 2) - { - mutexValue |= HasListenersMask; - } - - newOwnerThread.SignaledObj = null; - newOwnerThread.ObjSyncResult = Result.Success; - - newOwnerThread.ReleaseAndResume(); - } - - return (mutexValue, newOwnerThread); - } - - public void SignalProcessWideKey(ulong address, int count) - { - _context.CriticalSection.Enter(); - - WakeThreads(_condVarThreads, count, TryAcquireMutex, x => x.CondVarAddress == address); - - if (!_condVarThreads.Any(x => x.CondVarAddress == address)) - { - KernelTransfer.KernelToUser(address, 0); - } - - _context.CriticalSection.Leave(); - } - - private static void TryAcquireMutex(KThread requester) - { - ulong address = requester.MutexAddress; - - KProcess currentProcess = KernelStatic.GetCurrentProcess(); - - if (!currentProcess.CpuMemory.IsMapped(address)) - { - // Invalid address. - requester.SignaledObj = null; - requester.ObjSyncResult = KernelResult.InvalidMemState; - - return; - } - - ref int mutexRef = ref currentProcess.CpuMemory.GetRef<int>(address); - - int mutexValue, newMutexValue; - - do - { - mutexValue = mutexRef; - - if (mutexValue != 0) - { - // Update value to indicate there is a mutex waiter now. - newMutexValue = mutexValue | HasListenersMask; - } - else - { - // No thread owning the mutex, assign to requesting thread. - newMutexValue = requester.ThreadHandleForUserMutex; - } - } - while (Interlocked.CompareExchange(ref mutexRef, newMutexValue, mutexValue) != mutexValue); - - if (mutexValue == 0) - { - // We now own the mutex. - requester.SignaledObj = null; - requester.ObjSyncResult = Result.Success; - - requester.ReleaseAndResume(); - - return; - } - - mutexValue &= ~HasListenersMask; - - KThread mutexOwner = currentProcess.HandleTable.GetObject<KThread>(mutexValue); - - if (mutexOwner != null) - { - // Mutex already belongs to another thread, wait for it. - mutexOwner.AddMutexWaiter(requester); - } - else - { - // Invalid mutex owner. - requester.SignaledObj = null; - requester.ObjSyncResult = KernelResult.InvalidHandle; - - requester.ReleaseAndResume(); - } - } - - public Result WaitForAddressIfEqual(ulong address, int value, long timeout) - { - KThread currentThread = KernelStatic.GetCurrentThread(); - - _context.CriticalSection.Enter(); - - if (currentThread.TerminationRequested) - { - _context.CriticalSection.Leave(); - - return KernelResult.ThreadTerminating; - } - - currentThread.SignaledObj = null; - currentThread.ObjSyncResult = KernelResult.TimedOut; - - if (!KernelTransfer.UserToKernel(out int currentValue, address)) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidMemState; - } - - if (currentValue == value) - { - if (timeout == 0) - { - _context.CriticalSection.Leave(); - - return KernelResult.TimedOut; - } - - currentThread.MutexAddress = address; - currentThread.WaitingInArbitration = true; - - _arbiterThreads.Add(currentThread); - - currentThread.Reschedule(ThreadSchedState.Paused); - - if (timeout > 0) - { - _context.TimeManager.ScheduleFutureInvocation(currentThread, timeout); - } - - _context.CriticalSection.Leave(); - - if (timeout > 0) - { - _context.TimeManager.UnscheduleFutureInvocation(currentThread); - } - - _context.CriticalSection.Enter(); - - if (currentThread.WaitingInArbitration) - { - _arbiterThreads.Remove(currentThread); - - currentThread.WaitingInArbitration = false; - } - - _context.CriticalSection.Leave(); - - return currentThread.ObjSyncResult; - } - - _context.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - - public Result WaitForAddressIfLessThan(ulong address, int value, bool shouldDecrement, long timeout) - { - KThread currentThread = KernelStatic.GetCurrentThread(); - - _context.CriticalSection.Enter(); - - if (currentThread.TerminationRequested) - { - _context.CriticalSection.Leave(); - - return KernelResult.ThreadTerminating; - } - - currentThread.SignaledObj = null; - currentThread.ObjSyncResult = KernelResult.TimedOut; - - KProcess currentProcess = KernelStatic.GetCurrentProcess(); - - if (!KernelTransfer.UserToKernel(out int currentValue, address)) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidMemState; - } - - if (shouldDecrement) - { - currentValue = Interlocked.Decrement(ref currentProcess.CpuMemory.GetRef<int>(address)) + 1; - } - - if (currentValue < value) - { - if (timeout == 0) - { - _context.CriticalSection.Leave(); - - return KernelResult.TimedOut; - } - - currentThread.MutexAddress = address; - currentThread.WaitingInArbitration = true; - - _arbiterThreads.Add(currentThread); - - currentThread.Reschedule(ThreadSchedState.Paused); - - if (timeout > 0) - { - _context.TimeManager.ScheduleFutureInvocation(currentThread, timeout); - } - - _context.CriticalSection.Leave(); - - if (timeout > 0) - { - _context.TimeManager.UnscheduleFutureInvocation(currentThread); - } - - _context.CriticalSection.Enter(); - - if (currentThread.WaitingInArbitration) - { - _arbiterThreads.Remove(currentThread); - - currentThread.WaitingInArbitration = false; - } - - _context.CriticalSection.Leave(); - - return currentThread.ObjSyncResult; - } - - _context.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - - public Result Signal(ulong address, int count) - { - _context.CriticalSection.Enter(); - - WakeArbiterThreads(address, count); - - _context.CriticalSection.Leave(); - - return Result.Success; - } - - public Result SignalAndIncrementIfEqual(ulong address, int value, int count) - { - _context.CriticalSection.Enter(); - - KProcess currentProcess = KernelStatic.GetCurrentProcess(); - - if (!currentProcess.CpuMemory.IsMapped(address)) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidMemState; - } - - ref int valueRef = ref currentProcess.CpuMemory.GetRef<int>(address); - - int currentValue; - - do - { - currentValue = valueRef; - - if (currentValue != value) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - } - while (Interlocked.CompareExchange(ref valueRef, currentValue + 1, currentValue) != currentValue); - - WakeArbiterThreads(address, count); - - _context.CriticalSection.Leave(); - - return Result.Success; - } - - public Result SignalAndModifyIfEqual(ulong address, int value, int count) - { - _context.CriticalSection.Enter(); - - int addend; - - // The value is decremented if the number of threads waiting is less - // or equal to the Count of threads to be signaled, or Count is zero - // or negative. It is incremented if there are no threads waiting. - int waitingCount = 0; - - foreach (KThread thread in _arbiterThreads.Where(x => x.MutexAddress == address)) - { - if (++waitingCount >= count) - { - break; - } - } - - if (waitingCount > 0) - { - if (count <= 0) - { - addend = -2; - } - else if (waitingCount < count) - { - addend = -1; - } - else - { - addend = 0; - } - } - else - { - addend = 1; - } - - KProcess currentProcess = KernelStatic.GetCurrentProcess(); - - if (!currentProcess.CpuMemory.IsMapped(address)) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidMemState; - } - - ref int valueRef = ref currentProcess.CpuMemory.GetRef<int>(address); - - int currentValue; - - do - { - currentValue = valueRef; - - if (currentValue != value) - { - _context.CriticalSection.Leave(); - - return KernelResult.InvalidState; - } - } - while (Interlocked.CompareExchange(ref valueRef, currentValue + addend, currentValue) != currentValue); - - WakeArbiterThreads(address, count); - - _context.CriticalSection.Leave(); - - return Result.Success; - } - - private void WakeArbiterThreads(ulong address, int count) - { - static void RemoveArbiterThread(KThread thread) - { - thread.SignaledObj = null; - thread.ObjSyncResult = Result.Success; - - thread.ReleaseAndResume(); - - thread.WaitingInArbitration = false; - } - - WakeThreads(_arbiterThreads, count, RemoveArbiterThread, x => x.MutexAddress == address); - } - - private static void WakeThreads( - List<KThread> threads, - int count, - Action<KThread> removeCallback, - Func<KThread, bool> predicate) - { - var candidates = threads.Where(predicate).OrderBy(x => x.DynamicPriority); - var toSignal = (count > 0 ? candidates.Take(count) : candidates).ToArray(); - - foreach (KThread thread in toSignal) - { - removeCallback(thread); - threads.Remove(thread); - } - } - } -} |
