From 770cb4b655356816babab12c32af70fee61277d7 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 19 Feb 2018 16:37:13 -0300 Subject: [PATCH] Somewhat better scheduler I guess --- Ryujinx/Cpu/AThread.cs | 4 +- Ryujinx/Cpu/Memory/AMemoryHelper.cs | 27 -- Ryujinx/Hid.cs | 2 +- Ryujinx/OsHle/CondVar.cs | 85 +++-- Ryujinx/OsHle/Handles/KProcessScheduler.cs | 385 ++++++++++----------- Ryujinx/OsHle/Mutex.cs | 45 ++- Ryujinx/OsHle/Process.cs | 9 +- Ryujinx/OsHle/Svc/SvcSystem.cs | 21 +- Ryujinx/OsHle/Svc/SvcThread.cs | 10 +- Ryujinx/OsHle/Svc/SvcThreadSync.cs | 17 +- 10 files changed, 323 insertions(+), 282 deletions(-) diff --git a/Ryujinx/Cpu/AThread.cs b/Ryujinx/Cpu/AThread.cs index d86b025a..5c032289 100644 --- a/Ryujinx/Cpu/AThread.cs +++ b/Ryujinx/Cpu/AThread.cs @@ -7,8 +7,8 @@ namespace ChocolArm64 { public class AThread { - public AThreadState ThreadState { get; private set; } - public AMemory Memory { get; private set; } + public AThreadState ThreadState { get; private set; } + public AMemory Memory { get; private set; } public long EntryPoint { get; private set; } diff --git a/Ryujinx/Cpu/Memory/AMemoryHelper.cs b/Ryujinx/Cpu/Memory/AMemoryHelper.cs index fb4316c5..219aeebf 100644 --- a/Ryujinx/Cpu/Memory/AMemoryHelper.cs +++ b/Ryujinx/Cpu/Memory/AMemoryHelper.cs @@ -1,6 +1,5 @@ using System.IO; using System.Text; -using System.Threading; namespace ChocolArm64.Memory { @@ -21,32 +20,6 @@ namespace ChocolArm64.Memory } } - public static int ReadInt32Exclusive(AMemory Memory, long Position) - { - while (!Memory.AcquireAddress(Position)) - { - Thread.Yield(); - } - - int Value = Memory.ReadInt32(Position); - - Memory.ReleaseAddress(Position); - - return Value; - } - - public static void WriteInt32Exclusive(AMemory Memory, long Position, int Value) - { - while (!Memory.AcquireAddress(Position)) - { - Thread.Yield(); - } - - Memory.WriteInt32(Position, Value); - - Memory.ReleaseAddress(Position); - } - public static byte[] ReadBytes(AMemory Memory, long Position, int Size) { byte[] Data = new byte[Size]; diff --git a/Ryujinx/Hid.cs b/Ryujinx/Hid.cs index dc969f19..c344ec58 100644 --- a/Ryujinx/Hid.cs +++ b/Ryujinx/Hid.cs @@ -43,7 +43,7 @@ namespace Ryujinx } public void Init(long HidOffset) - { + { unsafe { if (HidOffset == 0 || HidOffset + Horizon.HidSize > uint.MaxValue) diff --git a/Ryujinx/OsHle/CondVar.cs b/Ryujinx/OsHle/CondVar.cs index eba8e4b0..91ea37bd 100644 --- a/Ryujinx/OsHle/CondVar.cs +++ b/Ryujinx/OsHle/CondVar.cs @@ -1,6 +1,6 @@ -using ChocolArm64.Memory; using Ryujinx.OsHle.Handles; using System.Collections.Generic; +using System.Threading; namespace Ryujinx.OsHle { @@ -11,6 +11,8 @@ namespace Ryujinx.OsHle private long CondVarAddress; private long Timeout; + private bool OwnsCondVarValue; + private List WaitingThreads; public CondVar(Process Process, long CondVarAddress, long Timeout) @@ -24,34 +26,43 @@ namespace Ryujinx.OsHle public void WaitForSignal(HThread Thread) { - int Count = ReadCondVarValue(); + int Count = Process.Memory.ReadInt32(CondVarAddress); if (Count <= 0) { - //FIXME: We shouldn't need to do that? - Process.Scheduler.Yield(Thread); + lock (WaitingThreads) + { + WaitingThreads.Add(Thread); + } - return; + if (Timeout == -1) + { + Process.Scheduler.WaitForSignal(Thread); + } + else + { + Process.Scheduler.WaitForSignal(Thread, (int)(Timeout / 1000000)); + + lock (WaitingThreads) + { + WaitingThreads.Remove(Thread); + } + } } - WriteCondVarValue(Count - 1); + AcquireCondVarValue(); - lock (WaitingThreads) + Count = Process.Memory.ReadInt32(CondVarAddress); + + if (Count > 0) { - WaitingThreads.Add(Thread); + Process.Memory.WriteInt32(CondVarAddress, Count - 1); } - if (Timeout != -1) - { - Process.Scheduler.WaitForSignal(Thread, (int)(Timeout / 1000000)); - } - else - { - Process.Scheduler.WaitForSignal(Thread); - } + ReleaseCondVarValue(); } - public void SetSignal(int Count) + public void SetSignal(HThread Thread, int Count) { lock (WaitingThreads) { @@ -59,7 +70,11 @@ namespace Ryujinx.OsHle { Process.Scheduler.Signal(WaitingThreads.ToArray()); - WriteCondVarValue(WaitingThreads.Count); + AcquireCondVarValue(); + + Process.Memory.WriteInt32(CondVarAddress, WaitingThreads.Count); + + ReleaseCondVarValue(); WaitingThreads.Clear(); } @@ -85,19 +100,39 @@ namespace Ryujinx.OsHle WaitingThreads.RemoveAt(HighestPrioIndex); } - WriteCondVarValue(Count); + AcquireCondVarValue(); + + Process.Memory.WriteInt32(CondVarAddress, Count); + + ReleaseCondVarValue(); } } + + Process.Scheduler.Suspend(Thread.ProcessorId); + Process.Scheduler.Resume(Thread); + } + + private void AcquireCondVarValue() + { + if (!OwnsCondVarValue) + { + while (!Process.Memory.AcquireAddress(CondVarAddress)) + { + Thread.Yield(); + } + + OwnsCondVarValue = true; + } } - private int ReadCondVarValue() + private void ReleaseCondVarValue() { - return AMemoryHelper.ReadInt32Exclusive(Process.Memory, CondVarAddress); - } + if (OwnsCondVarValue) + { + OwnsCondVarValue = false; - private void WriteCondVarValue(int Value) - { - AMemoryHelper.WriteInt32Exclusive(Process.Memory, CondVarAddress, Value); + Process.Memory.ReleaseAddress(CondVarAddress); + } } } } \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/KProcessScheduler.cs b/Ryujinx/OsHle/Handles/KProcessScheduler.cs index ca612de9..9044987f 100644 --- a/Ryujinx/OsHle/Handles/KProcessScheduler.cs +++ b/Ryujinx/OsHle/Handles/KProcessScheduler.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; @@ -6,19 +7,8 @@ namespace Ryujinx.OsHle.Handles { class KProcessScheduler : IDisposable { - private enum ThreadState - { - WaitingToRun, - WaitingSignal, - Running - } - private class SchedulerThread : IDisposable { - public bool Signaled { get; set; } - - public ThreadState State { get; set; } - public HThread Thread { get; private set; } public AutoResetEvent WaitEvent { get; private set; } @@ -44,9 +34,70 @@ namespace Ryujinx.OsHle.Handles } } - private Dictionary AllThreads; + private class ThreadQueue + { + private List Threads; - private Queue[] WaitingThreads; + public ThreadQueue() + { + Threads = new List(); + } + + public void Push(SchedulerThread Thread) + { + lock (Threads) + { + Threads.Add(Thread); + } + } + + public SchedulerThread Pop(int MinPriority = 0x40) + { + lock (Threads) + { + SchedulerThread SchedThread; + + int HighestPriority = MinPriority; + + int HighestPrioIndex = -1; + + for (int Index = 0; Index < Threads.Count; Index++) + { + SchedThread = Threads[Index]; + + if (HighestPriority > SchedThread.Thread.Priority) + { + HighestPriority = SchedThread.Thread.Priority; + + HighestPrioIndex = Index; + } + } + + if (HighestPrioIndex == -1) + { + return null; + } + + SchedThread = Threads[HighestPrioIndex]; + + Threads.RemoveAt(HighestPrioIndex); + + return SchedThread; + } + } + + public bool HasThread(SchedulerThread SchedThread) + { + lock (Threads) + { + return Threads.Contains(SchedThread); + } + } + } + + private ConcurrentDictionary AllThreads; + + private ThreadQueue[] WaitingToRun; private HashSet ActiveProcessors; @@ -54,13 +105,13 @@ namespace Ryujinx.OsHle.Handles public KProcessScheduler() { - AllThreads = new Dictionary(); + AllThreads = new ConcurrentDictionary(); - WaitingThreads = new Queue[4]; + WaitingToRun = new ThreadQueue[4]; - for (int Index = 0; Index < WaitingThreads.Length; Index++) + for (int Index = 0; Index < 4; Index++) { - WaitingThreads[Index] = new Queue(); + WaitingToRun[Index] = new ThreadQueue(); } ActiveProcessors = new HashSet(); @@ -72,132 +123,171 @@ namespace Ryujinx.OsHle.Handles { lock (SchedLock) { - if (AllThreads.ContainsKey(Thread)) + SchedulerThread SchedThread = new SchedulerThread(Thread); + + if (!AllThreads.TryAdd(Thread, SchedThread)) { return; } - SchedulerThread SchedThread = new SchedulerThread(Thread); - - AllThreads.Add(Thread, SchedThread); - if (!ActiveProcessors.Contains(Thread.ProcessorId)) { ActiveProcessors.Add(Thread.ProcessorId); Thread.Thread.Execute(); - SetThreadAsRunning(SchedThread); - - SchedThread.State = ThreadState.Running; + Logging.Debug($"{GetDbgThreadInfo(Thread)} running."); } else { - InsertSorted(SchedThread); - - SchedThread.State = ThreadState.WaitingToRun; + WaitingToRun[Thread.ProcessorId].Push(SchedThread); Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} waiting to run."); } } } - public void WaitForSignal(HThread Thread, int TimeoutMs) + public void Suspend(int ProcessorId) { - Logging.Debug($"{GetDbgThreadInfo(Thread)} entering signal wait state with timeout."); + lock (SchedLock) + { + SchedulerThread SchedThread = WaitingToRun[ProcessorId].Pop(); - PutThreadToWait(Thread, ThreadState.WaitingSignal, TimeoutMs); + if (SchedThread != null) + { + RunThread(SchedThread); + } + else + { + ActiveProcessors.Remove(ProcessorId); + } + } } - public void WaitForSignal(HThread Thread) + public void Resume(HThread CurrThread) { + SchedulerThread SchedThread; + + Logging.Debug($"{GetDbgThreadInfo(CurrThread)} entering ipc delay wait state."); + + lock (SchedLock) + { + if (!AllThreads.TryGetValue(CurrThread, out SchedThread)) + { + Logging.Error($"{GetDbgThreadInfo(CurrThread)} was not found on the scheduler queue!"); + + return; + } + } + + TryResumingExecution(SchedThread); + } + + public void WaitForSignal(HThread Thread, int Timeout = -1) + { + SchedulerThread SchedThread; + Logging.Debug($"{GetDbgThreadInfo(Thread)} entering signal wait state."); - PutThreadToWait(Thread, ThreadState.WaitingSignal); + lock (SchedLock) + { + SchedThread = WaitingToRun[Thread.ProcessorId].Pop(); + + if (SchedThread != null) + { + RunThread(SchedThread); + } + else + { + ActiveProcessors.Remove(Thread.ProcessorId); + } + + if (!AllThreads.TryGetValue(Thread, out SchedThread)) + { + Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!"); + + return; + } + } + + if (Timeout >= 0) + { + Logging.Debug($"{GetDbgThreadInfo(Thread)} has wait timeout of {Timeout}ms."); + + SchedThread.WaitEvent.WaitOne(Timeout); + } + else + { + SchedThread.WaitEvent.WaitOne(); + } + + TryResumingExecution(SchedThread); + } + + private void TryResumingExecution(SchedulerThread SchedThread) + { + HThread Thread = SchedThread.Thread; + + lock (SchedLock) + { + if (ActiveProcessors.Add(Thread.ProcessorId)) + { + Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); + + return; + } + + WaitingToRun[Thread.ProcessorId].Push(SchedThread); + } + + SchedThread.WaitEvent.WaitOne(); + + Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); } public void Yield(HThread Thread) - { - Logging.Debug($"{GetDbgThreadInfo(Thread)} yielded execution."); - - if (WaitingThreads[Thread.ProcessorId].Count == 0) - { - Logging.Debug($"{GetDbgThreadInfo(Thread)} resumed because theres nothing to run."); - - return; - } - - PutThreadToWait(Thread, ThreadState.WaitingToRun); - } - - private void PutThreadToWait(HThread Thread, ThreadState State, int TimeoutMs = -1) { SchedulerThread SchedThread; + Logging.Debug($"{GetDbgThreadInfo(Thread)} yielded execution."); + lock (SchedLock) { + SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority); + + if (SchedThread == null) + { + Logging.Debug($"{GetDbgThreadInfo(Thread)} resumed because theres nothing better to run."); + + return; + } + + RunThread(SchedThread); + if (!AllThreads.TryGetValue(Thread, out SchedThread)) { - return; - } - - if (SchedThread.Signaled && SchedThread.State == ThreadState.WaitingSignal) - { - SchedThread.Signaled = false; + Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!"); return; } - ActiveProcessors.Remove(Thread.ProcessorId); - - SchedThread.State = State; - - TryRunningWaitingThead(SchedThread.Thread.ProcessorId); - - if (State == ThreadState.WaitingSignal) - { - InsertSorted(SchedThread); - } - else - { - InsertAtEnd(SchedThread); - } + WaitingToRun[Thread.ProcessorId].Push(SchedThread); } - if (TimeoutMs >= 0) - { - Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} waiting with timeout of {TimeoutMs}ms."); + SchedThread.WaitEvent.WaitOne(); - SchedThread.WaitEvent.WaitOne(TimeoutMs); + Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); + } + + private void RunThread(SchedulerThread SchedThread) + { + if (!SchedThread.Thread.Thread.Execute()) + { + SchedThread.WaitEvent.Set(); } else { - Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} waiting indefinitely."); - - SchedThread.WaitEvent.WaitOne(); - } - - while (true) - { - lock (SchedLock) - { - Logging.Debug($"Trying to run {GetDbgThreadInfo(SchedThread.Thread)}."); - - if (!ActiveProcessors.Contains(SchedThread.Thread.ProcessorId)) - { - SetThreadAsRunning(SchedThread); - - break; - } - else - { - SchedThread.State = ThreadState.WaitingToRun; - - Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} waiting to run."); - } - } - - SchedThread.WaitEvent.WaitOne(); + Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} running."); } } @@ -205,107 +295,21 @@ namespace Ryujinx.OsHle.Handles { lock (SchedLock) { - HashSet SignaledProcessorIds = new HashSet(); - foreach (HThread Thread in Threads) { - Logging.Debug($"{GetDbgThreadInfo(Thread)} signaled."); - if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) { - if (SchedThread.State == ThreadState.WaitingSignal) + if (!WaitingToRun[Thread.ProcessorId].HasThread(SchedThread)) { - SchedThread.State = ThreadState.WaitingToRun; + Logging.Debug($"{GetDbgThreadInfo(Thread)} signaled."); - SignaledProcessorIds.Add(Thread.ProcessorId); + SchedThread.WaitEvent.Set(); } - - SchedThread.Signaled = true; } } - - foreach (int ProcessorId in SignaledProcessorIds) - { - TryRunningWaitingThead(ProcessorId); - } } } - private void TryRunningWaitingThead(int ProcessorId) - { - Logging.Debug($"TryRunningWaitingThead core {ProcessorId}."); - - lock (SchedLock) - { - if (!ActiveProcessors.Contains(ProcessorId) && WaitingThreads[ProcessorId].Count > 0) - { - SchedulerThread SchedThread = WaitingThreads[ProcessorId].Dequeue(); - - Logging.Debug($"Now trying to run {GetDbgThreadInfo(SchedThread.Thread)}."); - - if (!SchedThread.Thread.Thread.Execute()) - { - SchedThread.WaitEvent.Set(); - } - else - { - SetThreadAsRunning(SchedThread); - } - } - else - { - Logging.Debug($"Processor id {ProcessorId} already being used or no waiting threads."); - } - } - } - - private void SetThreadAsRunning(SchedulerThread SchedThread) - { - ActiveProcessors.Add(SchedThread.Thread.ProcessorId); - - SchedThread.State = ThreadState.Running; - - SchedThread.Signaled = false; - - Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} running."); - } - - private void InsertSorted(SchedulerThread SchedThread) - { - HThread Thread = SchedThread.Thread; - - Queue CoreQueue = WaitingThreads[Thread.ProcessorId]; - - Queue TempQueue = new Queue(CoreQueue.Count); - - while (CoreQueue.Count > 0) - { - if (CoreQueue.Peek().Thread.Priority >= Thread.Priority) - { - break; - } - - TempQueue.Enqueue(CoreQueue.Dequeue()); - } - - CoreQueue.Enqueue(SchedThread); - - while (CoreQueue.Count > 0) - { - TempQueue.Enqueue(CoreQueue.Dequeue()); - } - - while (TempQueue.Count > 0) - { - CoreQueue.Enqueue(TempQueue.Dequeue()); - } - } - - private void InsertAtEnd(SchedulerThread SchedThread) - { - WaitingThreads[SchedThread.Thread.ProcessorId].Enqueue(SchedThread); - } - private string GetDbgThreadInfo(HThread Thread) { return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}"; @@ -320,14 +324,9 @@ namespace Ryujinx.OsHle.Handles { if (Disposing) { - foreach (Queue SchedThreads in WaitingThreads) + foreach (SchedulerThread SchedThread in AllThreads.Values) { - foreach (SchedulerThread SchedThread in SchedThreads) - { - SchedThread.Dispose(); - } - - SchedThreads.Clear(); + SchedThread.Dispose(); } } } diff --git a/Ryujinx/OsHle/Mutex.cs b/Ryujinx/OsHle/Mutex.cs index f8344b6f..43862d7b 100644 --- a/Ryujinx/OsHle/Mutex.cs +++ b/Ryujinx/OsHle/Mutex.cs @@ -1,6 +1,6 @@ -using ChocolArm64.Memory; using Ryujinx.OsHle.Handles; using System.Collections.Concurrent; +using System.Threading; namespace Ryujinx.OsHle { @@ -12,6 +12,8 @@ namespace Ryujinx.OsHle private long MutexAddress; + private bool OwnsMutexValue; + private object EnterWaitLock; private ConcurrentQueue WaitingThreads; @@ -30,9 +32,11 @@ namespace Ryujinx.OsHle public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle) { + AcquireMutexValue(); + lock (EnterWaitLock) { - int CurrentThreadHandle = ReadMutexValue() & ~MutexHasListenersMask; + int CurrentThreadHandle = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask; if (CurrentThreadHandle == RequestingThreadHandle || CurrentThreadHandle == 0) @@ -40,7 +44,9 @@ namespace Ryujinx.OsHle return; } - WriteMutexValue(CurrentThreadHandle | MutexHasListenersMask); + Process.Memory.WriteInt32(MutexAddress, CurrentThreadHandle | MutexHasListenersMask); + + ReleaseMutexValue(); WaitingThreads.Enqueue(RequestingThread); } @@ -50,24 +56,32 @@ namespace Ryujinx.OsHle public void GiveUpLock(int ThreadHandle) { + AcquireMutexValue(); + lock (EnterWaitLock) { - int CurrentThread = ReadMutexValue() & ~MutexHasListenersMask; + int CurrentThread = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask; if (CurrentThread == ThreadHandle) { Unlock(); } } + + ReleaseMutexValue(); } public void Unlock() { + AcquireMutexValue(); + lock (EnterWaitLock) { int HasListeners = WaitingThreads.Count > 1 ? MutexHasListenersMask : 0; - WriteMutexValue(HasListeners); + Process.Memory.WriteInt32(MutexAddress, HasListeners); + + ReleaseMutexValue(); HThread[] UnlockedThreads = new HThread[WaitingThreads.Count]; @@ -82,14 +96,27 @@ namespace Ryujinx.OsHle } } - private int ReadMutexValue() + private void AcquireMutexValue() { - return AMemoryHelper.ReadInt32Exclusive(Process.Memory, MutexAddress); + if (!OwnsMutexValue) + { + while (!Process.Memory.AcquireAddress(MutexAddress)) + { + Thread.Yield(); + } + + OwnsMutexValue = true; + } } - private void WriteMutexValue(int Value) + private void ReleaseMutexValue() { - AMemoryHelper.WriteInt32Exclusive(Process.Memory, MutexAddress, Value); + if (OwnsMutexValue) + { + OwnsMutexValue = false; + + Process.Memory.ReleaseAddress(MutexAddress); + } } } } \ No newline at end of file diff --git a/Ryujinx/OsHle/Process.cs b/Ryujinx/OsHle/Process.cs index f8c41dd3..4d07b94b 100644 --- a/Ryujinx/OsHle/Process.cs +++ b/Ryujinx/OsHle/Process.cs @@ -231,9 +231,14 @@ namespace Ryujinx.OsHle return (int)((Position - TlsPageAddr) / TlsSize); } - public bool TryGetThread(long Tpidr, out HThread Thread) + public HThread GetThread(long Tpidr) { - return ThreadsByTpidr.TryGetValue(Tpidr, out Thread); + if (!ThreadsByTpidr.TryGetValue(Tpidr, out HThread Thread)) + { + Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!"); + } + + return Thread; } public void Dispose() diff --git a/Ryujinx/OsHle/Svc/SvcSystem.cs b/Ryujinx/OsHle/Svc/SvcSystem.cs index 9451ae07..0570ccb0 100644 --- a/Ryujinx/OsHle/Svc/SvcSystem.cs +++ b/Ryujinx/OsHle/Svc/SvcSystem.cs @@ -4,6 +4,7 @@ using Ryujinx.OsHle.Exceptions; using Ryujinx.OsHle.Handles; using Ryujinx.OsHle.Ipc; using System; +using System.Threading; namespace Ryujinx.OsHle.Svc { @@ -37,16 +38,10 @@ namespace Ryujinx.OsHle.Svc //TODO: Implement events. - //Logging.Info($"SvcWaitSynchronization Thread {ThreadState.ThreadId}"); + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); - if (Process.TryGetThread(ThreadState.Tpidr, out HThread Thread)) - { - Process.Scheduler.Yield(Thread); - } - else - { - Logging.Error($"Thread with TPIDR_EL0 0x{ThreadState.Tpidr:x16} not found!"); - } + Process.Scheduler.Suspend(CurrThread.ProcessorId); + Process.Scheduler.Resume(CurrThread); ThreadState.X0 = (int)SvcResult.Success; } @@ -99,6 +94,10 @@ namespace Ryujinx.OsHle.Svc Handle = (int)ThreadState.X0; } + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + Process.Scheduler.Suspend(CurrThread.ProcessorId); + byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size); HSession Session = Ns.Os.Handles.GetData(Handle); @@ -117,6 +116,10 @@ namespace Ryujinx.OsHle.Svc { ThreadState.X0 = (int)SvcResult.ErrBadIpcReq; } + + Thread.Yield(); + + Process.Scheduler.Resume(CurrThread); } private void SvcBreak(AThreadState ThreadState) diff --git a/Ryujinx/OsHle/Svc/SvcThread.cs b/Ryujinx/OsHle/Svc/SvcThread.cs index c5ea59b9..cc2bbb1e 100644 --- a/Ryujinx/OsHle/Svc/SvcThread.cs +++ b/Ryujinx/OsHle/Svc/SvcThread.cs @@ -1,6 +1,5 @@ using ChocolArm64.State; using Ryujinx.OsHle.Handles; -using System.Threading; namespace Ryujinx.OsHle.Svc { @@ -18,6 +17,7 @@ namespace Ryujinx.OsHle.Svc { if (ProcessorId == -2) { + //TODO: Get this value from the NPDM file. ProcessorId = 0; } @@ -55,16 +55,16 @@ namespace Ryujinx.OsHle.Svc { ulong NanoSecs = ThreadState.X0; - if (Process.TryGetThread(ThreadState.Tpidr, out HThread CurrThread)) + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + if (NanoSecs == 0) { Process.Scheduler.Yield(CurrThread); } else { - Logging.Error($"Thread with TPIDR_EL0 0x{ThreadState.Tpidr:x16} not found!"); + Process.Scheduler.WaitForSignal(CurrThread, (int)(NanoSecs / 1000000)); } - - Thread.Sleep((int)(NanoSecs / 1000000)); } private void SvcGetThreadPriority(AThreadState ThreadState) diff --git a/Ryujinx/OsHle/Svc/SvcThreadSync.cs b/Ryujinx/OsHle/Svc/SvcThreadSync.cs index b7108e8f..f342f51d 100644 --- a/Ryujinx/OsHle/Svc/SvcThreadSync.cs +++ b/Ryujinx/OsHle/Svc/SvcThreadSync.cs @@ -43,10 +43,11 @@ namespace Ryujinx.OsHle.Svc HThread Thread = Ns.Os.Handles.GetData(ThreadHandle); - if (Ns.Os.Mutexes.TryGetValue(MutexAddress, out Mutex M)) - { - M.GiveUpLock(ThreadHandle); - } + Mutex M = new Mutex(Process, MutexAddress, ThreadHandle); + + M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M); + + M.GiveUpLock(ThreadHandle); CondVar Cv = new CondVar(Process, CondVarAddress, Timeout); @@ -54,10 +55,6 @@ namespace Ryujinx.OsHle.Svc Cv.WaitForSignal(Thread); - M = new Mutex(Process, MutexAddress, ThreadHandle); - - M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M); - M.WaitForLock(Thread, ThreadHandle); ThreadState.X0 = (int)SvcResult.Success; @@ -68,9 +65,11 @@ namespace Ryujinx.OsHle.Svc long CondVarAddress = (long)ThreadState.X0; int Count = (int)ThreadState.X1; + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv)) { - Cv.SetSignal(Count); + Cv.SetSignal(CurrThread, Count); } ThreadState.X0 = (int)SvcResult.Success;