From 770cb4b655356816babab12c32af70fee61277d7 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
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 d86b025a39..5c03228943 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 fb4316c543..219aeebf9e 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 dc969f19ae..c344ec5877 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 eba8e4b056..91ea37bdb2 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<HThread> 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 ca612de999..9044987fdc 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<HThread, SchedulerThread> AllThreads;
+        private class ThreadQueue
+        {
+            private List<SchedulerThread> Threads;
 
-        private Queue<SchedulerThread>[] WaitingThreads;
+            public ThreadQueue()
+            {
+                Threads = new List<SchedulerThread>();
+            }
+
+            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<HThread, SchedulerThread> AllThreads;
+
+        private ThreadQueue[] WaitingToRun;
 
         private HashSet<int> ActiveProcessors;
 
@@ -54,13 +105,13 @@ namespace Ryujinx.OsHle.Handles
 
         public KProcessScheduler()
         {
-            AllThreads = new Dictionary<HThread, SchedulerThread>();
+            AllThreads = new ConcurrentDictionary<HThread, SchedulerThread>();
 
-            WaitingThreads = new Queue<SchedulerThread>[4];
+            WaitingToRun = new ThreadQueue[4];
 
-            for (int Index = 0; Index < WaitingThreads.Length; Index++)
+            for (int Index = 0; Index < 4; Index++)
             {
-                WaitingThreads[Index] = new Queue<SchedulerThread>();
+                WaitingToRun[Index] = new ThreadQueue();
             }
 
             ActiveProcessors = new HashSet<int>();
@@ -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<int> SignaledProcessorIds = new HashSet<int>();
-
                 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<SchedulerThread> CoreQueue = WaitingThreads[Thread.ProcessorId];
-
-            Queue<SchedulerThread> TempQueue = new Queue<SchedulerThread>(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<SchedulerThread> 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 f8344b6f26..43862d7b2b 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<HThread> 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 f8c41dd3a1..4d07b94bd9 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 9451ae07e9..0570ccb09e 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<HSession>(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 c5ea59b9df..cc2bbb1eb3 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 b7108e8fee..f342f51d58 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<HThread>(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;