From 33ae6e544bd477da629e3f4ab4925f457ecfbbb7 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Thu, 19 Apr 2018 04:06:23 -0300 Subject: [PATCH] [HLE/Kernel] Fix SetThreadPriority, allow nano seconds values > int.MaxValue, fix on WaitProcessWideKeyAtomic (althrough looks like it still doesn't work properly --- .../OsHle/Kernel/ConditionVariable.cs | 10 +++------- Ryujinx.Core/OsHle/Kernel/MutualExclusion.cs | 8 ++++++-- Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs | 19 +++++++++++++++++++ Ryujinx.Core/OsHle/Kernel/SvcSystem.cs | 10 +++++----- Ryujinx.Core/OsHle/Kernel/SvcThread.cs | 12 ++++++------ Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs | 12 ++++++++---- 6 files changed, 47 insertions(+), 24 deletions(-) create mode 100644 Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs diff --git a/Ryujinx.Core/OsHle/Kernel/ConditionVariable.cs b/Ryujinx.Core/OsHle/Kernel/ConditionVariable.cs index 4e64a154ed..91ed91587c 100644 --- a/Ryujinx.Core/OsHle/Kernel/ConditionVariable.cs +++ b/Ryujinx.Core/OsHle/Kernel/ConditionVariable.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Core.OsHle.Kernel WaitingThreads = new List<(KThread, AutoResetEvent)>(); } - public bool WaitForSignal(KThread Thread, long Timeout) + public bool WaitForSignal(KThread Thread, ulong Timeout) { bool Result = true; @@ -37,23 +37,19 @@ namespace Ryujinx.Core.OsHle.Kernel WaitingThreads.Add((Thread, WaitEvent)); } - Process.Scheduler.Suspend(Thread.ProcessorId); - - if (Timeout < 0) + if (Timeout == ulong.MaxValue) { Result = WaitEvent.WaitOne(); } else { - Result = WaitEvent.WaitOne((int)(Timeout / 1000000)); + Result = WaitEvent.WaitOne(NsTimeConverter.GetTimeMs(Timeout)); lock (WaitingThreads) { WaitingThreads.Remove((Thread, WaitEvent)); } } - - Process.Scheduler.Resume(Thread); } } diff --git a/Ryujinx.Core/OsHle/Kernel/MutualExclusion.cs b/Ryujinx.Core/OsHle/Kernel/MutualExclusion.cs index aeaaf70f9c..9f05406b8f 100644 --- a/Ryujinx.Core/OsHle/Kernel/MutualExclusion.cs +++ b/Ryujinx.Core/OsHle/Kernel/MutualExclusion.cs @@ -12,6 +12,8 @@ namespace Ryujinx.Core.OsHle.Kernel private long MutexAddress; + private int OwnerThreadHandle; + private List<(KThread Thread, AutoResetEvent WaitEvent)> WaitingThreads; public MutualExclusion(Process Process, long MutexAddress) @@ -24,8 +26,6 @@ namespace Ryujinx.Core.OsHle.Kernel public void WaitForLock(KThread RequestingThread) { - int OwnerThreadHandle = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask; - WaitForLock(RequestingThread, OwnerThreadHandle); } @@ -80,10 +80,14 @@ namespace Ryujinx.Core.OsHle.Kernel WaitingThreads.RemoveAt(HighestPrioIndex); Process.Memory.WriteInt32(MutexAddress, HasListeners | Handle); + + OwnerThreadHandle = Handle; } else { Process.Memory.WriteInt32(MutexAddress, 0); + + OwnerThreadHandle = 0; } } } diff --git a/Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs b/Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs new file mode 100644 index 0000000000..84fb0b85ea --- /dev/null +++ b/Ryujinx.Core/OsHle/Kernel/NsTimeConverter.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.Core.OsHle.Kernel +{ + static class NsTimeConverter + { + public static int GetTimeMs(ulong Ns) + { + ulong Ms = Ns / 1_000_000; + + if (Ms < int.MaxValue) + { + return (int)Ms; + } + else + { + return int.MaxValue; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs index ebbbef4aaf..48e8ce385a 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcSystem.cs @@ -83,9 +83,9 @@ namespace Ryujinx.Core.OsHle.Kernel private void SvcWaitSynchronization(AThreadState ThreadState) { - long HandlesPtr = (long)ThreadState.X1; - int HandlesCount = (int)ThreadState.X2; - long Timeout = (long)ThreadState.X3; + long HandlesPtr = (long)ThreadState.X1; + int HandlesCount = (int)ThreadState.X2; + ulong Timeout = ThreadState.X3; KThread CurrThread = Process.GetThread(ThreadState.Tpidr); @@ -115,9 +115,9 @@ namespace Ryujinx.Core.OsHle.Kernel ulong Result = 0; - if (Timeout != -1) + if (Timeout != ulong.MaxValue) { - HandleIndex = WaitHandle.WaitAny(Handles, (int)(Timeout / 1000000)); + HandleIndex = WaitHandle.WaitAny(Handles, NsTimeConverter.GetTimeMs(Timeout)); if (HandleIndex == WaitHandle.WaitTimeout) { diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs index 7418732fa1..2534c9d99d 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs @@ -64,11 +64,11 @@ namespace Ryujinx.Core.OsHle.Kernel private void SvcSleepThread(AThreadState ThreadState) { - ulong NanoSecs = ThreadState.X0; + ulong Ns = ThreadState.X0; KThread CurrThread = Process.GetThread(ThreadState.Tpidr); - if (NanoSecs == 0) + if (Ns == 0) { Process.Scheduler.Yield(CurrThread); } @@ -76,7 +76,7 @@ namespace Ryujinx.Core.OsHle.Kernel { Process.Scheduler.Suspend(CurrThread.ProcessorId); - Thread.Sleep((int)(NanoSecs / 1000000)); + Thread.Sleep(NsTimeConverter.GetTimeMs(Ns)); Process.Scheduler.Resume(CurrThread); } @@ -103,14 +103,14 @@ namespace Ryujinx.Core.OsHle.Kernel private void SvcSetThreadPriority(AThreadState ThreadState) { - int Prio = (int)ThreadState.X0; - int Handle = (int)ThreadState.X1; + int Handle = (int)ThreadState.X0; + int Priority = (int)ThreadState.X1; KThread CurrThread = Process.HandleTable.GetData(Handle); if (CurrThread != null) { - CurrThread.Priority = Prio; + CurrThread.Priority = Priority; ThreadState.X0 = 0; } diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs index e9d801b424..38d759d35a 100644 --- a/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs +++ b/Ryujinx.Core/OsHle/Kernel/SvcThreadSync.cs @@ -55,10 +55,10 @@ namespace Ryujinx.Core.OsHle.Kernel private void SvcWaitProcessWideKeyAtomic(AThreadState ThreadState) { - long MutexAddress = (long)ThreadState.X0; - long CondVarAddress = (long)ThreadState.X1; - int ThreadHandle = (int)ThreadState.X2; - long Timeout = (long)ThreadState.X3; + long MutexAddress = (long)ThreadState.X0; + long CondVarAddress = (long)ThreadState.X1; + int ThreadHandle = (int)ThreadState.X2; + ulong Timeout = ThreadState.X3; KThread Thread = Process.HandleTable.GetData(ThreadHandle); @@ -69,6 +69,8 @@ namespace Ryujinx.Core.OsHle.Kernel ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); } + Process.Scheduler.Suspend(Thread.ProcessorId); + MutualExclusion Mutex = GetMutex(MutexAddress); Mutex.Unlock(); @@ -82,6 +84,8 @@ namespace Ryujinx.Core.OsHle.Kernel Mutex.WaitForLock(Thread); + Process.Scheduler.Resume(Thread); + ThreadState.X0 = 0; }