diff --git a/Ryujinx.Core/OsHle/Handles/KThread.cs b/Ryujinx.Core/OsHle/Handles/KThread.cs index 146c800ec2..d593b0a965 100644 --- a/Ryujinx.Core/OsHle/Handles/KThread.cs +++ b/Ryujinx.Core/OsHle/Handles/KThread.cs @@ -18,7 +18,7 @@ namespace Ryujinx.Core.OsHle.Handles private int DesiredPriority; - public int Handle { get; set; } + public int WaitHandle { get; set; } public int ThreadId => Thread.ThreadId; diff --git a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs index 015163939d..c74da061a5 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcHandler.cs @@ -17,6 +17,8 @@ namespace Ryujinx.Core.OsHle.Kernel private Process Process; private AMemory Memory; + private object CondVarLock; + private HashSet<(HSharedMem, long)> MappedSharedMems; private ulong CurrentHeapSize; @@ -67,6 +69,8 @@ namespace Ryujinx.Core.OsHle.Kernel this.Process = Process; this.Memory = Process.Memory; + CondVarLock = new object(); + MappedSharedMems = new HashSet<(HSharedMem, long)>(); } diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs index aad40c9948..f1a1178398 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs @@ -13,9 +13,9 @@ namespace Ryujinx.Core.OsHle.Kernel private void SvcArbitrateLock(AThreadState ThreadState) { - int OwnerThreadHandle = (int)ThreadState.X0; - long MutexAddress = (long)ThreadState.X1; - int RequestingThreadHandle = (int)ThreadState.X2; + int OwnerThreadHandle = (int)ThreadState.X0; + long MutexAddress = (long)ThreadState.X1; + int WaitThreadHandle = (int)ThreadState.X2; if (IsPointingInsideKernel(MutexAddress)) { @@ -46,18 +46,20 @@ namespace Ryujinx.Core.OsHle.Kernel return; } - KThread RequestingThread = Process.HandleTable.GetData(RequestingThreadHandle); + KThread WaitThread = Process.HandleTable.GetData(WaitThreadHandle); - if (RequestingThread == null) + if (WaitThread == null) { - Logging.Warn(LogClass.KernelSvc, $"Invalid requesting thread handle 0x{RequestingThreadHandle:x8}!"); + Logging.Warn(LogClass.KernelSvc, $"Invalid requesting thread handle 0x{WaitThreadHandle:x8}!"); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return; } - MutexLock(MutexAddress, RequestingThread, OwnerThreadHandle); + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + MutexLock(CurrThread, WaitThread, OwnerThreadHandle, WaitThreadHandle, MutexAddress); ThreadState.X0 = 0; } @@ -128,9 +130,11 @@ namespace Ryujinx.Core.OsHle.Kernel return; } - MutexUnlock(Process.GetThread(ThreadState.Tpidr), MutexAddress); + KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - if (!CondVarWait(Thread, MutexAddress, CondVarAddress, Timeout)) + MutexUnlock(CurrThread, MutexAddress); + + if (!CondVarWait(CurrThread, ThreadHandle, MutexAddress, CondVarAddress, Timeout)) { ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.Timeout); @@ -152,7 +156,12 @@ namespace Ryujinx.Core.OsHle.Kernel ThreadState.X0 = 0; } - private void MutexLock(long MutexAddress, KThread RequestingThread, int OwnerThreadHandle) + private void MutexLock( + KThread CurrThread, + KThread WaitThread, + int OwnerThreadHandle, + int WaitThreadHandle, + long MutexAddress) { int MutexValue = Process.Memory.ReadInt32(MutexAddress); @@ -161,11 +170,12 @@ namespace Ryujinx.Core.OsHle.Kernel return; } - InsertWaitingMutexThread(OwnerThreadHandle, RequestingThread); + CurrThread.WaitHandle = WaitThreadHandle; + CurrThread.MutexAddress = MutexAddress; - RequestingThread.MutexAddress = MutexAddress; + InsertWaitingMutexThread(OwnerThreadHandle, WaitThread); - Process.Scheduler.EnterWait(RequestingThread); + Process.Scheduler.EnterWait(WaitThread); } private bool MutexUnlock(KThread CurrThread, long MutexAddress) @@ -177,11 +187,6 @@ namespace Ryujinx.Core.OsHle.Kernel return false; } - CurrThread.MutexAddress = 0; - CurrThread.CondVarAddress = 0; - - CurrThread.ResetPriority(); - KThread OwnerThread = CurrThread.NextMutexThread; CurrThread.NextMutexThread = null; @@ -190,7 +195,13 @@ namespace Ryujinx.Core.OsHle.Kernel { int HasListeners = OwnerThread.NextMutexThread != null ? MutexHasListenersMask : 0; - Process.Memory.WriteInt32(MutexAddress, HasListeners | OwnerThread.Handle); + Process.Memory.WriteInt32(MutexAddress, HasListeners | OwnerThread.WaitHandle); + + OwnerThread.WaitHandle = 0; + OwnerThread.MutexAddress = 0; + OwnerThread.CondVarAddress = 0; + + OwnerThread.ResetPriority(); Process.Scheduler.WakeUp(OwnerThread); @@ -204,43 +215,52 @@ namespace Ryujinx.Core.OsHle.Kernel } } - private bool CondVarWait(KThread WaitThread, long MutexAddress, long CondVarAddress, ulong Timeout) + private bool CondVarWait( + KThread WaitThread, + int WaitThreadHandle, + long MutexAddress, + long CondVarAddress, + ulong Timeout) { - KThread CurrThread = Process.ThreadArbiterList; + WaitThread.WaitHandle = WaitThreadHandle; + WaitThread.MutexAddress = MutexAddress; + WaitThread.CondVarAddress = CondVarAddress; - if (CurrThread != null) + lock (CondVarLock) { - bool DoInsert = CurrThread != WaitThread; + KThread CurrThread = Process.ThreadArbiterList; - while (CurrThread.NextCondVarThread != null) + if (CurrThread != null) { - if (CurrThread.NextCondVarThread.Priority < WaitThread.Priority) + bool DoInsert = CurrThread != WaitThread; + + while (CurrThread.NextCondVarThread != null) { - break; + if (CurrThread.NextCondVarThread.Priority < WaitThread.Priority) + { + break; + } + + CurrThread = CurrThread.NextCondVarThread; + + DoInsert &= CurrThread != WaitThread; } - CurrThread = CurrThread.NextCondVarThread; - - DoInsert &= CurrThread != WaitThread; - } - - if (DoInsert) - { - if (WaitThread.NextCondVarThread != null) + if (DoInsert) { - throw new InvalidOperationException(); + if (WaitThread.NextCondVarThread != null) + { + throw new InvalidOperationException(); + } + + WaitThread.NextCondVarThread = CurrThread.NextCondVarThread; + CurrThread.NextCondVarThread = WaitThread; } - - WaitThread.NextCondVarThread = CurrThread.NextCondVarThread; - CurrThread.NextCondVarThread = WaitThread; } - - CurrThread.MutexAddress = MutexAddress; - CurrThread.CondVarAddress = CondVarAddress; - } - else - { - Process.ThreadArbiterList = WaitThread; + else + { + Process.ThreadArbiterList = WaitThread; + } } if (Timeout != ulong.MaxValue) @@ -255,95 +275,106 @@ namespace Ryujinx.Core.OsHle.Kernel private void CondVarSignal(long CondVarAddress, int Count) { - KThread PrevThread = null; - KThread CurrThread = Process.ThreadArbiterList; - - while (CurrThread != null && (Count == -1 || Count-- > 0)) + lock (CondVarLock) { - if (CurrThread.CondVarAddress == CondVarAddress) + KThread PrevThread = null; + KThread CurrThread = Process.ThreadArbiterList; + + while (CurrThread != null && (Count == -1 || Count > 0)) { - if (PrevThread != null) + if (CurrThread.CondVarAddress == CondVarAddress) { - PrevThread.NextCondVarThread = CurrThread.NextCondVarThread; - } - else - { - Process.ThreadArbiterList = CurrThread.NextCondVarThread; + if (PrevThread != null) + { + PrevThread.NextCondVarThread = CurrThread.NextCondVarThread; + } + else + { + Process.ThreadArbiterList = CurrThread.NextCondVarThread; + } + + CurrThread.NextCondVarThread = null; + + AcquireMutexValue(CurrThread.MutexAddress); + + int MutexValue = Process.Memory.ReadInt32(CurrThread.MutexAddress); + + MutexValue &= ~MutexHasListenersMask; + + if (MutexValue == 0) + { + Process.Memory.WriteInt32(CurrThread.MutexAddress, CurrThread.WaitHandle); + + CurrThread.WaitHandle = 0; + CurrThread.MutexAddress = 0; + CurrThread.CondVarAddress = 0; + + CurrThread.ResetPriority(); + + Process.Scheduler.WakeUp(CurrThread); + } + else + { + InsertWaitingMutexThread(MutexValue, CurrThread); + + MutexValue |= MutexHasListenersMask; + + Process.Memory.WriteInt32(CurrThread.MutexAddress, MutexValue); + } + + ReleaseMutexValue(CurrThread.MutexAddress); + + Count--; } - CurrThread.NextCondVarThread = null; - - AcquireMutexValue(CurrThread.MutexAddress); - - int MutexValue = Process.Memory.ReadInt32(CurrThread.MutexAddress); - - MutexValue &= ~MutexHasListenersMask; - - if (MutexValue == 0) - { - Process.Memory.WriteInt32(CurrThread.MutexAddress, CurrThread.Handle); - - CurrThread.MutexAddress = 0; - CurrThread.CondVarAddress = 0; - - CurrThread.ResetPriority(); - - Process.Scheduler.WakeUp(CurrThread); - } - else - { - InsertWaitingMutexThread(MutexValue, CurrThread); - - MutexValue |= MutexHasListenersMask; - - Process.Memory.WriteInt32(CurrThread.MutexAddress, MutexValue); - } - - ReleaseMutexValue(CurrThread.MutexAddress); + PrevThread = CurrThread; + CurrThread = CurrThread.NextCondVarThread; } - - PrevThread = CurrThread; - CurrThread = CurrThread.NextCondVarThread; } } private void InsertWaitingMutexThread(int OwnerThreadHandle, KThread WaitThread) { - KThread CurrThread = Process.HandleTable.GetData(OwnerThreadHandle); + KThread OwnerThread = Process.HandleTable.GetData(OwnerThreadHandle); - if (CurrThread == null) + if (OwnerThread == null) { Logging.Warn(LogClass.KernelSvc, $"Invalid thread handle 0x{OwnerThreadHandle:x8}!"); return; } - while (CurrThread.NextMutexThread != null) + lock (OwnerThread) { - if (CurrThread == WaitThread) + KThread CurrThread = OwnerThread; + + while (CurrThread.NextMutexThread != null) { - return; + if (CurrThread == WaitThread) + { + return; + } + + if (CurrThread.NextMutexThread.Priority < WaitThread.Priority) + { + break; + } + + CurrThread = CurrThread.NextMutexThread; } - if (CurrThread.NextMutexThread.Priority < WaitThread.Priority) + if (CurrThread != WaitThread) { - break; + if (WaitThread.NextCondVarThread != null) + { + throw new InvalidOperationException(); + } + + WaitThread.NextMutexThread = CurrThread.NextMutexThread; + CurrThread.NextMutexThread = WaitThread; + + CurrThread.UpdatePriority(); } - - CurrThread = CurrThread.NextMutexThread; - } - - if (CurrThread != WaitThread) - { - if (WaitThread.NextCondVarThread != null) - { - throw new InvalidOperationException(); - } - - WaitThread.NextMutexThread = CurrThread.NextMutexThread; - CurrThread.NextMutexThread = WaitThread; - - CurrThread.UpdatePriority(); } } diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index 06a7fcf8c3..bd4ff1ff20 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -10,7 +10,6 @@ using Ryujinx.Core.OsHle.Services.Nv; using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; namespace Ryujinx.Core.OsHle { @@ -194,8 +193,6 @@ namespace Ryujinx.Core.OsHle int Handle = HandleTable.OpenHandle(Thread); - Thread.Handle = Handle; - int ThreadId = GetFreeTlsSlot(CpuThread); long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize; @@ -335,28 +332,6 @@ namespace Ryujinx.Core.OsHle return Thread; } - public IEnumerable EnumerateThreadsWithMutex(long MutexAddress) - { - foreach (KThread Thread in Threads.Values.OrderBy(x => x.Priority)) - { - if (Thread.MutexAddress == MutexAddress) - { - yield return Thread; - } - } - } - - public IEnumerable EnumerateThreadsWithCondVar(long CondVarAddress) - { - foreach (KThread Thread in Threads.Values.OrderBy(x => x.Priority)) - { - if (Thread.CondVarAddress == CondVarAddress) - { - yield return Thread; - } - } - } - public void Dispose() { Dispose(true);