diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index f8ec89140e..d52c8af0a2 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -71,6 +71,8 @@ namespace Ryujinx.HLE.HOS
 
             Withholders = new LinkedList<KThread>();
 
+            Scheduler.StartAutoPreemptionThread();
+
             if (!Device.Memory.Allocator.TryAllocate(HidSize,  out long HidPA) ||
                 !Device.Memory.Allocator.TryAllocate(FontSize, out long FontPA))
             {
@@ -212,7 +214,7 @@ namespace Ryujinx.HLE.HOS
             }
 
             MainNca.SetBaseNca(PatchNca);
-            
+
             if (ControlNca != null)
             {
                 ReadControlData(ControlNca);
@@ -466,7 +468,7 @@ namespace Ryujinx.HLE.HOS
 
         public void SignalVsync()
         {
-            VsyncEvent.Signal();
+            VsyncEvent.ReadableEvent.Signal();
         }
 
         private Process MakeProcess(Npdm MetaData = null)
diff --git a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs
index 08a4cdb5d0..fca995c08a 100644
--- a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs
+++ b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs
@@ -73,7 +73,10 @@ namespace Ryujinx.HLE.HOS.Ipc
                         {
                             int Unknown = ReqReader.ReadInt32();
 
-                            int Handle = Process.HandleTable.OpenHandle(Session);
+                            if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
+                            {
+                                throw new InvalidOperationException("Out of handles!");
+                            }
 
                             Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs b/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs
index 42caeca2d5..e0cb158c98 100644
--- a/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs
+++ b/Ryujinx.HLE/HOS/Kernel/HleScheduler.cs
@@ -15,6 +15,15 @@ namespace Ryujinx.HLE.HOS.Kernel
 
         private bool KeepPreempting;
 
+        public void StartAutoPreemptionThread()
+        {
+            Thread PreemptionThread = new Thread(PreemptCurrentThread);
+
+            KeepPreempting = true;
+
+            PreemptionThread.Start();
+        }
+
         public void ContextSwitch()
         {
             lock (CoreContexts)
diff --git a/Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs b/Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs
index f2156a5c20..73309e1e26 100644
--- a/Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KAddressArbiter.cs
@@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel
                 return 0;
             }
 
-            KThread MutexOwner = Process.HandleTable.GetData<KThread>(OwnerHandle);
+            KThread MutexOwner = Process.HandleTable.GetObject<KThread>(OwnerHandle);
 
             if (MutexOwner == null)
             {
@@ -282,7 +282,7 @@ namespace Ryujinx.HLE.HOS.Kernel
 
             MutexValue &= ~HasListenersMask;
 
-            KThread MutexOwner = Process.HandleTable.GetData<KThread>(MutexValue);
+            KThread MutexOwner = Process.HandleTable.GetObject<KThread>(MutexValue);
 
             if (MutexOwner != null)
             {
diff --git a/Ryujinx.HLE/HOS/Kernel/KEvent.cs b/Ryujinx.HLE/HOS/Kernel/KEvent.cs
index 1a865aa202..106d1b4092 100644
--- a/Ryujinx.HLE/HOS/Kernel/KEvent.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KEvent.cs
@@ -1,38 +1,14 @@
 namespace Ryujinx.HLE.HOS.Kernel
 {
-    class KEvent : KSynchronizationObject
+    class KEvent
     {
-        private bool Signaled;
+        public KReadableEvent ReadableEvent { get; private set; }
+        public KWritableEvent WritableEvent { get; private set; }
 
-        public string Name { get; private set; }
-
-        public KEvent(Horizon System, string Name = "") : base(System)
+        public KEvent(Horizon System)
         {
-            this.Name = Name;
-        }
-
-        public override void Signal()
-        {
-            System.CriticalSectionLock.Lock();
-
-            if (!Signaled)
-            {
-                Signaled = true;
-
-                base.Signal();
-            }
-
-            System.CriticalSectionLock.Unlock();
-        }
-
-        public void Reset()
-        {
-            Signaled = false;
-        }
-
-        public override bool IsSignaled()
-        {
-            return Signaled;
+            ReadableEvent = new KReadableEvent(System, this);
+            WritableEvent = new KWritableEvent(this);
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs b/Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs
new file mode 100644
index 0000000000..9863a374bd
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.HLE.HOS.Kernel
+{
+    class KHandleEntry
+    {
+        public KHandleEntry Next { get; set; }
+
+        public int Index { get; private set; }
+
+        public ushort HandleId { get; set; }
+        public object Obj      { get; set; }
+
+        public KHandleEntry(int Index)
+        {
+            this.Index = Index;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs b/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs
index db0eaa44f9..682f08d4ff 100644
--- a/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs
@@ -1,34 +1,183 @@
-using System.Collections.Generic;
+using System;
 
 namespace Ryujinx.HLE.HOS.Kernel
 {
     class KProcessHandleTable
     {
-        private IdDictionary Handles;
+        private const int SelfThreadHandle  = (0x1ffff << 15) | 0;
+        private const int SelfProcessHandle = (0x1ffff << 15) | 1;
 
-        public KProcessHandleTable()
+        private Horizon System;
+
+        private KHandleEntry[] Table;
+
+        private KHandleEntry TableHead;
+        private KHandleEntry NextFreeEntry;
+
+        private int ActiveSlotsCount;
+
+        private int Size;
+
+        private ushort IdCounter;
+
+        private object LockObj;
+
+        public KProcessHandleTable(Horizon System, int Size = 1024)
         {
-            Handles = new IdDictionary();
+            this.System = System;
+            this.Size   = Size;
+
+            IdCounter = 1;
+
+            Table = new KHandleEntry[Size];
+
+            TableHead = new KHandleEntry(0);
+
+            KHandleEntry Entry = TableHead;
+
+            for (int Index = 0; Index < Size; Index++)
+            {
+                Table[Index] = Entry;
+
+                Entry.Next = new KHandleEntry(Index + 1);
+
+                Entry = Entry.Next;
+            }
+
+            Table[Size - 1].Next = null;
+
+            NextFreeEntry = TableHead;
+
+            LockObj = new object();
         }
 
-        public int OpenHandle(object Obj)
+        public KernelResult GenerateHandle(object Obj, out int Handle)
         {
-            return Handles.Add(Obj);
+            Handle = 0;
+
+            lock (LockObj)
+            {
+                if (ActiveSlotsCount >= Size)
+                {
+                    return KernelResult.HandleTableFull;
+                }
+
+                KHandleEntry Entry = NextFreeEntry;
+
+                NextFreeEntry = Entry.Next;
+
+                Entry.Obj      = Obj;
+                Entry.HandleId = IdCounter;
+
+                ActiveSlotsCount++;
+
+                Handle = (int)((IdCounter << 15) & (uint)0xffff8000) | Entry.Index;
+
+                if ((short)(IdCounter + 1) >= 0)
+                {
+                    IdCounter++;
+                }
+                else
+                {
+                    IdCounter = 1;
+                }
+            }
+
+            return KernelResult.Success;
         }
 
-        public T GetData<T>(int Handle)
+        public bool CloseHandle(int Handle)
         {
-            return Handles.GetData<T>(Handle);
+            if ((Handle >> 30) != 0 ||
+                Handle == SelfThreadHandle ||
+                Handle == SelfProcessHandle)
+            {
+                return false;
+            }
+
+            int Index    = (Handle >>  0) & 0x7fff;
+            int HandleId = (Handle >> 15);
+
+            bool Result = false;
+
+            lock (LockObj)
+            {
+                if (HandleId != 0 && Index < Size)
+                {
+                    KHandleEntry Entry = Table[Index];
+
+                    if (Entry.Obj != null && Entry.HandleId == HandleId)
+                    {
+                        Entry.Obj  = null;
+                        Entry.Next = NextFreeEntry;
+
+                        NextFreeEntry = Entry;
+
+                        ActiveSlotsCount--;
+
+                        Result = true;
+                    }
+                }
+            }
+
+            return Result;
         }
 
-        public object CloseHandle(int Handle)
+        public T GetObject<T>(int Handle)
         {
-            return Handles.Delete(Handle);
+            int Index    = (Handle >>  0) & 0x7fff;
+            int HandleId = (Handle >> 15);
+
+            lock (LockObj)
+            {
+                if ((Handle >> 30) == 0 && HandleId != 0)
+                {
+                    KHandleEntry Entry = Table[Index];
+
+                    if (Entry.HandleId == HandleId && Entry.Obj is T Obj)
+                    {
+                        return Obj;
+                    }
+                }
+            }
+
+            return default(T);
         }
 
-        public ICollection<object> Clear()
+        public KThread GetKThread(int Handle)
         {
-            return Handles.Clear();
+            if (Handle == SelfThreadHandle)
+            {
+                return System.Scheduler.GetCurrentThread();
+            }
+            else
+            {
+                return GetObject<KThread>(Handle);
+            }
+        }
+
+        public void Destroy()
+        {
+            lock (LockObj)
+            {
+                for (int Index = 0; Index < Size; Index++)
+                {
+                    KHandleEntry Entry = Table[Index];
+
+                    if (Entry.Obj != null)
+                    {
+                        if (Entry.Obj is IDisposable DisposableObj)
+                        {
+                            DisposableObj.Dispose();
+                        }
+
+                        Entry.Obj  = null;
+                        Entry.Next = NextFreeEntry;
+
+                        NextFreeEntry = Entry;
+                    }
+                }
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs b/Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs
new file mode 100644
index 0000000000..d43fe8249e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs
@@ -0,0 +1,62 @@
+namespace Ryujinx.HLE.HOS.Kernel
+{
+    class KReadableEvent : KSynchronizationObject
+    {
+        private KEvent Parent;
+
+        private bool Signaled;
+
+        public KReadableEvent(Horizon System, KEvent Parent) : base(System)
+        {
+            this.Parent = Parent;
+        }
+
+        public override void Signal()
+        {
+            System.CriticalSectionLock.Lock();
+
+            if (!Signaled)
+            {
+                Signaled = true;
+
+                base.Signal();
+            }
+
+            System.CriticalSectionLock.Unlock();
+        }
+
+        public KernelResult Clear()
+        {
+            Signaled = false;
+
+            return KernelResult.Success;
+        }
+
+        public KernelResult ClearIfSignaled()
+        {
+            KernelResult Result;
+
+            System.CriticalSectionLock.Lock();
+
+            if (Signaled)
+            {
+                Signaled = false;
+
+                Result = KernelResult.Success;
+            }
+            else
+            {
+                Result = KernelResult.InvalidState;
+            }
+
+            System.CriticalSectionLock.Unlock();
+
+            return Result;
+        }
+
+        public override bool IsSignaled()
+        {
+            return Signaled;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/KScheduler.cs b/Ryujinx.HLE/HOS/Kernel/KScheduler.cs
index f6382d05d6..3cfda4197f 100644
--- a/Ryujinx.HLE/HOS/Kernel/KScheduler.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KScheduler.cs
@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using System.Threading;
 
 namespace Ryujinx.HLE.HOS.Kernel
 {
@@ -35,12 +34,6 @@ namespace Ryujinx.HLE.HOS.Kernel
             {
                 CoreContexts[Core] = new KCoreContext(this, CoreManager);
             }
-
-            Thread PreemptionThread = new Thread(PreemptCurrentThread);
-
-            KeepPreempting = true;
-
-            PreemptionThread.Start();
         }
 
         private void PreemptThreads()
diff --git a/Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs b/Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs
new file mode 100644
index 0000000000..1721ed0011
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs
@@ -0,0 +1,22 @@
+namespace Ryujinx.HLE.HOS.Kernel
+{
+    class KWritableEvent
+    {
+        private KEvent Parent;
+
+        public KWritableEvent(KEvent Parent)
+        {
+            this.Parent = Parent;
+        }
+
+        public void Signal()
+        {
+            Parent.ReadableEvent.Signal();
+        }
+
+        public KernelResult Clear()
+        {
+            return Parent.ReadableEvent.Clear();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/KernelErr.cs b/Ryujinx.HLE/HOS/Kernel/KernelErr.cs
index 0749f3fd08..e0b196f412 100644
--- a/Ryujinx.HLE/HOS/Kernel/KernelErr.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KernelErr.cs
@@ -6,6 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel
         public const int InvalidSize       = 101;
         public const int InvalidAddress    = 102;
         public const int OutOfMemory       = 104;
+        public const int HandleTableFull   = 105;
         public const int NoAccessPerm      = 106;
         public const int InvalidPermission = 108;
         public const int InvalidMemRange   = 110;
diff --git a/Ryujinx.HLE/HOS/Kernel/KernelResult.cs b/Ryujinx.HLE/HOS/Kernel/KernelResult.cs
new file mode 100644
index 0000000000..d9cbfc6735
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/KernelResult.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.HLE.HOS.Kernel
+{
+    enum KernelResult
+    {
+        Success         = 0,
+        HandleTableFull = 0xd201,
+        InvalidHandle   = 0xe401,
+        InvalidState    = 0xfa01
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs b/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs
index a12a0ba0f3..b678037b9e 100644
--- a/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SvcHandler.cs
@@ -39,9 +39,6 @@ namespace Ryujinx.HLE.HOS.Kernel
             }
         }
 
-        private const uint SelfThreadHandle  = 0xffff8000;
-        private const uint SelfProcessHandle = 0xffff8001;
-
         private static Random Rng;
 
         public SvcHandler(Switch Device, Process Process)
@@ -63,12 +60,13 @@ namespace Ryujinx.HLE.HOS.Kernel
                 { 0x0e, SvcGetThreadCoreMask             },
                 { 0x0f, SvcSetThreadCoreMask             },
                 { 0x10, SvcGetCurrentProcessorNumber     },
-                { 0x12, SvcClearEvent                    },
+                { 0x11, SignalEvent64                    },
+                { 0x12, ClearEvent64                     },
                 { 0x13, SvcMapSharedMemory               },
                 { 0x14, SvcUnmapSharedMemory             },
                 { 0x15, SvcCreateTransferMemory          },
                 { 0x16, SvcCloseHandle                   },
-                { 0x17, SvcResetSignal                   },
+                { 0x17, ResetSignal64                    },
                 { 0x18, SvcWaitSynchronization           },
                 { 0x19, SvcCancelSynchronization         },
                 { 0x1a, SvcArbitrateLock                 },
@@ -88,7 +86,8 @@ namespace Ryujinx.HLE.HOS.Kernel
                 { 0x32, SvcSetThreadActivity             },
                 { 0x33, SvcGetThreadContext3             },
                 { 0x34, SvcWaitForAddress                },
-                { 0x35, SvcSignalToAddress               }
+                { 0x35, SvcSignalToAddress               },
+                { 0x45, CreateEvent64                    }
             };
 
             this.Device  = Device;
@@ -123,17 +122,5 @@ namespace Ryujinx.HLE.HOS.Kernel
                 throw new NotImplementedException($"0x{e.Id:x4}");
             }
         }
-
-        private KThread GetThread(long Tpidr, int Handle)
-        {
-            if ((uint)Handle == SelfThreadHandle)
-            {
-                return Process.GetThread(Tpidr);
-            }
-            else
-            {
-                return Process.HandleTable.GetData<KThread>(Handle);
-            }
-        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs b/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs
index b9e71b183c..e3c0cf5b5b 100644
--- a/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SvcMemory.cs
@@ -276,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel
                 return;
             }
 
-            KSharedMemory SharedMemory = Process.HandleTable.GetData<KSharedMemory>(Handle);
+            KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
 
             if (SharedMemory == null)
             {
@@ -348,7 +348,7 @@ namespace Ryujinx.HLE.HOS.Kernel
                 return;
             }
 
-            KSharedMemory SharedMemory = Process.HandleTable.GetData<KSharedMemory>(Handle);
+            KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
 
             if (SharedMemory == null)
             {
@@ -425,9 +425,9 @@ namespace Ryujinx.HLE.HOS.Kernel
 
             KTransferMemory TransferMemory = new KTransferMemory(Position, Size);
 
-            int Handle = Process.HandleTable.OpenHandle(TransferMemory);
+            KernelResult Result = Process.HandleTable.GenerateHandle(TransferMemory, out int Handle);
 
-            ThreadState.X0 = 0;
+            ThreadState.X0 = (uint)Result;
             ThreadState.X1 = (ulong)Handle;
         }
 
diff --git a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs
index 60ccf7f7f8..8bcea55077 100644
--- a/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SvcSystem.cs
@@ -22,20 +22,73 @@ namespace Ryujinx.HLE.HOS.Kernel
             Device.System.ExitProcess(Process.ProcessId);
         }
 
-        private void SvcClearEvent(AThreadState ThreadState)
+        private void SignalEvent64(AThreadState ThreadState)
         {
-            int Handle = (int)ThreadState.X0;
+            ThreadState.X0 = (ulong)SignalEvent((int)ThreadState.X0);
+        }
 
-            //TODO: Implement events.
+        private KernelResult SignalEvent(int Handle)
+        {
+            KWritableEvent WritableEvent = Process.HandleTable.GetObject<KWritableEvent>(Handle);
 
-            ThreadState.X0 = 0;
+            KernelResult Result;
+
+            if (WritableEvent != null)
+            {
+                WritableEvent.Signal();
+
+                Result = KernelResult.Success;
+            }
+            else
+            {
+                Result = KernelResult.InvalidHandle;
+            }
+
+            if (Result != KernelResult.Success)
+            {
+                Device.Log.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
+            }
+
+            return Result;
+        }
+
+        private void ClearEvent64(AThreadState ThreadState)
+        {
+            ThreadState.X0 = (ulong)ClearEvent((int)ThreadState.X0);
+        }
+
+        private KernelResult ClearEvent(int Handle)
+        {
+            KernelResult Result;
+
+            KWritableEvent WritableEvent = Process.HandleTable.GetObject<KWritableEvent>(Handle);
+
+            if (WritableEvent == null)
+            {
+                KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
+
+                Result = ReadableEvent?.Clear() ?? KernelResult.InvalidHandle;
+            }
+            else
+            {
+                Result = WritableEvent.Clear();
+            }
+
+            if (Result != KernelResult.Success)
+            {
+                Device.Log.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
+            }
+
+            return Result;
         }
 
         private void SvcCloseHandle(AThreadState ThreadState)
         {
             int Handle = (int)ThreadState.X0;
 
-            object Obj = Process.HandleTable.CloseHandle(Handle);
+            object Obj = Process.HandleTable.GetObject<object>(Handle);
+
+            Process.HandleTable.CloseHandle(Handle);
 
             if (Obj == null)
             {
@@ -60,24 +113,37 @@ namespace Ryujinx.HLE.HOS.Kernel
             ThreadState.X0 = 0;
         }
 
-        private void SvcResetSignal(AThreadState ThreadState)
+        private void ResetSignal64(AThreadState ThreadState)
         {
-            int Handle = (int)ThreadState.X0;
+            ThreadState.X0 = (ulong)ResetSignal((int)ThreadState.X0);
+        }
 
-            KEvent Event = Process.HandleTable.GetData<KEvent>(Handle);
+        private KernelResult ResetSignal(int Handle)
+        {
+            KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
 
-            if (Event != null)
+            KernelResult Result;
+
+            //TODO: KProcess support.
+            if (ReadableEvent != null)
             {
-                Event.Reset();
-
-                ThreadState.X0 = 0;
+                Result = ReadableEvent.ClearIfSignaled();
             }
             else
             {
-                Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid event handle 0x{Handle:x8}!");
-
-                ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
+                Result = KernelResult.InvalidHandle;
             }
+
+            if (Result == KernelResult.InvalidState)
+            {
+                Device.Log.PrintDebug(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
+            }
+            else if (Result != KernelResult.Success)
+            {
+                Device.Log.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
+            }
+
+            return Result;
         }
 
         private void SvcGetSystemTick(AThreadState ThreadState)
@@ -96,10 +162,13 @@ namespace Ryujinx.HLE.HOS.Kernel
             //actually exists, return error codes otherwise.
             KSession Session = new KSession(ServiceFactory.MakeService(System, Name), Name);
 
-            ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
+            if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             ThreadState.X0 = 0;
-            ThreadState.X1 = Handle;
+            ThreadState.X1 = (uint)Handle;
         }
 
         private void SvcSendSyncRequest(AThreadState ThreadState)
@@ -122,7 +191,7 @@ namespace Ryujinx.HLE.HOS.Kernel
 
             byte[] MessageData = Memory.ReadBytes(MessagePtr, Size);
 
-            KSession Session = Process.HandleTable.GetData<KSession>(Handle);
+            KSession Session = Process.HandleTable.GetObject<KSession>(Handle);
 
             if (Session != null)
             {
@@ -206,7 +275,8 @@ namespace Ryujinx.HLE.HOS.Kernel
             if (InfoType == 18 ||
                 InfoType == 19 ||
                 InfoType == 20 ||
-                InfoType == 21)
+                InfoType == 21 ||
+                InfoType == 22)
             {
                 ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
 
@@ -287,5 +357,37 @@ namespace Ryujinx.HLE.HOS.Kernel
 
             ThreadState.X0 = 0;
         }
+
+        private void CreateEvent64(AThreadState State)
+        {
+            KernelResult Result = CreateEvent(out int WEventHandle, out int REventHandle);
+
+            State.X0 = (ulong)Result;
+            State.X1 = (ulong)WEventHandle;
+            State.X2 = (ulong)REventHandle;
+        }
+
+        private KernelResult CreateEvent(out int WEventHandle, out int REventHandle)
+        {
+            KEvent Event = new KEvent(System);
+
+            KernelResult Result = Process.HandleTable.GenerateHandle(Event.WritableEvent, out WEventHandle);
+
+            if (Result == KernelResult.Success)
+            {
+                Result = Process.HandleTable.GenerateHandle(Event.ReadableEvent, out REventHandle);
+
+                if (Result != KernelResult.Success)
+                {
+                    Process.HandleTable.CloseHandle(WEventHandle);
+                }
+            }
+            else
+            {
+                REventHandle = 0;
+            }
+
+            return Result;
+        }
     }
 }
diff --git a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs
index dc296b060e..d9273e23a2 100644
--- a/Ryujinx.HLE/HOS/Kernel/SvcThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SvcThread.cs
@@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Kernel
         {
             int Handle = (int)ThreadState.X0;
 
-            KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
+            KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
 
             if (Thread != null)
             {
@@ -112,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Kernel
         {
             int Handle = (int)ThreadState.X1;
 
-            KThread Thread = GetThread(ThreadState.Tpidr, Handle);
+            KThread Thread = Process.HandleTable.GetKThread(Handle);
 
             if (Thread != null)
             {
@@ -138,7 +138,7 @@ namespace Ryujinx.HLE.HOS.Kernel
 
             //TODO: NPDM check.
 
-            KThread Thread = GetThread(ThreadState.Tpidr, Handle);
+            KThread Thread = Process.HandleTable.GetKThread(Handle);
 
             if (Thread == null)
             {
@@ -160,7 +160,7 @@ namespace Ryujinx.HLE.HOS.Kernel
 
             Device.Log.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + Handle.ToString("x8"));
 
-            KThread Thread = GetThread(ThreadState.Tpidr, Handle);
+            KThread Thread = Process.HandleTable.GetKThread(Handle);
 
             if (Thread != null)
             {
@@ -178,12 +178,12 @@ namespace Ryujinx.HLE.HOS.Kernel
 
         private void SvcSetThreadCoreMask(AThreadState ThreadState)
         {
-            int  ThreadHandle  =  (int)ThreadState.X0;
+            int  Handle        =  (int)ThreadState.X0;
             int  PrefferedCore =  (int)ThreadState.X1;
             long AffinityMask  = (long)ThreadState.X2;
 
             Device.Log.PrintDebug(LogClass.KernelSvc,
-                "ThreadHandle = 0x"  + ThreadHandle .ToString("x8") + ", " +
+                "Handle = 0x"        + Handle       .ToString("x8") + ", " +
                 "PrefferedCore = 0x" + PrefferedCore.ToString("x8") + ", " +
                 "AffinityMask = 0x"  + AffinityMask .ToString("x16"));
 
@@ -219,11 +219,11 @@ namespace Ryujinx.HLE.HOS.Kernel
                 }
             }
 
-            KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle);
+            KThread Thread = Process.HandleTable.GetKThread(Handle);
 
             if (Thread == null)
             {
-                Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
+                Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
 
                 ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
 
@@ -249,7 +249,7 @@ namespace Ryujinx.HLE.HOS.Kernel
         {
             int Handle = (int)ThreadState.X1;
 
-            KThread Thread = GetThread(ThreadState.Tpidr, Handle);
+            KThread Thread = Process.HandleTable.GetKThread(Handle);
 
             if (Thread != null)
             {
@@ -269,7 +269,7 @@ namespace Ryujinx.HLE.HOS.Kernel
             int  Handle = (int)ThreadState.X0;
             bool Pause  = (int)ThreadState.X1 == 1;
 
-            KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
+            KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
 
             if (Thread == null)
             {
@@ -304,7 +304,7 @@ namespace Ryujinx.HLE.HOS.Kernel
             long Position = (long)ThreadState.X0;
             int  Handle   =  (int)ThreadState.X1;
 
-            KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
+            KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
 
             if (Thread == null)
             {
diff --git a/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs b/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs
index 868e017292..db9f6fb48b 100644
--- a/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SvcThreadSync.cs
@@ -1,5 +1,6 @@
 using ChocolArm64.State;
 using Ryujinx.HLE.Logging;
+using System.Collections.Generic;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
 
@@ -25,22 +26,27 @@ namespace Ryujinx.HLE.HOS.Kernel
                 return;
             }
 
-            KSynchronizationObject[] SyncObjs = new KSynchronizationObject[HandlesCount];
+            List<KSynchronizationObject> SyncObjs = new List<KSynchronizationObject>();
 
             for (int Index = 0; Index < HandlesCount; Index++)
             {
                 int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
 
-                KSynchronizationObject SyncObj = Process.HandleTable.GetData<KSynchronizationObject>(Handle);
+                KSynchronizationObject SyncObj = Process.HandleTable.GetObject<KSynchronizationObject>(Handle);
 
-                SyncObjs[Index] = SyncObj;
+                if (SyncObj == null)
+                {
+                    break;
+                }
+
+                SyncObjs.Add(SyncObj);
             }
 
             int HndIndex = (int)ThreadState.X1;
 
             ulong High = ThreadState.X1 & (0xffffffffUL << 32);
 
-            long Result = System.Synchronization.WaitFor(SyncObjs, Timeout, ref HndIndex);
+            long Result = System.Synchronization.WaitFor(SyncObjs.ToArray(), Timeout, ref HndIndex);
 
             if (Result != 0)
             {
@@ -65,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Kernel
 
             Device.Log.PrintDebug(LogClass.KernelSvc, "ThreadHandle = 0x" + ThreadHandle.ToString("x8"));
 
-            KThread Thread = Process.HandleTable.GetData<KThread>(ThreadHandle);
+            KThread Thread = Process.HandleTable.GetKThread(ThreadHandle);
 
             if (Thread == null)
             {
diff --git a/Ryujinx.HLE/HOS/Process.cs b/Ryujinx.HLE/HOS/Process.cs
index f7ec2604cc..3817f56195 100644
--- a/Ryujinx.HLE/HOS/Process.cs
+++ b/Ryujinx.HLE/HOS/Process.cs
@@ -71,7 +71,22 @@ namespace Ryujinx.HLE.HOS
 
             TlsPages = new List<KTlsPageManager>();
 
-            HandleTable = new KProcessHandleTable();
+            int HandleTableSize = 1024;
+
+            if (MetaData != null)
+            {
+                foreach (KernelAccessControlItem Item in MetaData.ACI0.KernelAccessControl.Items)
+                {
+                    if (Item.HasHandleTableSize)
+                    {
+                        HandleTableSize = Item.HandleTableSize;
+
+                        break;
+                    }
+                }
+            }
+
+            HandleTable = new KProcessHandleTable(Device.System, HandleTableSize);
 
             AppletState = new AppletStateMgr(Device.System);
 
@@ -139,7 +154,7 @@ namespace Ryujinx.HLE.HOS
                 return false;
             }
 
-            KThread MainThread = HandleTable.GetData<KThread>(Handle);
+            KThread MainThread = HandleTable.GetKThread(Handle);
 
             if (NeedsHbAbi)
             {
@@ -190,7 +205,7 @@ namespace Ryujinx.HLE.HOS
 
             Thread.LastPc = EntryPoint;
 
-            int Handle = HandleTable.OpenHandle(Thread);
+            HandleTable.GenerateHandle(Thread, out int Handle);
 
             CpuThread.ThreadState.CntfrqEl0 = TickFreq;
             CpuThread.ThreadState.Tpidr     = Tpidr;
@@ -427,13 +442,7 @@ namespace Ryujinx.HLE.HOS
 
             Disposed = true;
 
-            foreach (object Obj in HandleTable.Clear())
-            {
-                if (Obj is KSession Session)
-                {
-                    Session.Dispose();
-                }
-            }
+            HandleTable.Destroy();
 
             INvDrvServices.UnloadProcess(this);
 
diff --git a/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs
index 72049d6f44..4ea18d3298 100644
--- a/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/ICommonStateGetter.cs
@@ -1,6 +1,7 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.Logging;
+using System;
 using System.Collections.Generic;
 
 using static Ryujinx.HLE.HOS.ErrorCode;
@@ -36,7 +37,10 @@ namespace Ryujinx.HLE.HOS.Services.Am
         {
             KEvent Event = Context.Process.AppletState.MessageEvent;
 
-            int Handle = Context.Process.HandleTable.OpenHandle(Event);
+            if (Context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
@@ -103,7 +107,10 @@ namespace Ryujinx.HLE.HOS.Services.Am
 
         public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(DisplayResolutionChangeEvent);
+            if (Context.Process.HandleTable.GenerateHandle(DisplayResolutionChangeEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs
index 0c271796e8..a476aff97a 100644
--- a/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/IHomeMenuFunctions.cs
@@ -1,6 +1,7 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.Logging;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
@@ -34,7 +35,10 @@ namespace Ryujinx.HLE.HOS.Services.Am
 
         public long GetPopFromGeneralChannelEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(ChannelEvent);
+            if (Context.Process.HandleTable.GenerateHandle(ChannelEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs
index a9de3ebd45..07b8d97108 100644
--- a/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/ILibraryAppletAccessor.cs
@@ -1,6 +1,7 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.Logging;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
@@ -29,9 +30,12 @@ namespace Ryujinx.HLE.HOS.Services.Am
 
         public long GetAppletStateChangedEvent(ServiceCtx Context)
         {
-            StateChangedEvent.Signal();
+            StateChangedEvent.ReadableEvent.Signal();
 
-            int Handle = Context.Process.HandleTable.OpenHandle(StateChangedEvent);
+            if (Context.Process.HandleTable.GenerateHandle(StateChangedEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs b/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs
index fe8822735b..2c1d0c3bcc 100644
--- a/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/ISelfController.cs
@@ -1,6 +1,7 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.Logging;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Am
@@ -57,9 +58,12 @@ namespace Ryujinx.HLE.HOS.Services.Am
 
         public long GetLibraryAppletLaunchableEvent(ServiceCtx Context)
         {
-            LaunchableEvent.Signal();
+            LaunchableEvent.ReadableEvent.Signal();
 
-            int Handle = Context.Process.HandleTable.OpenHandle(LaunchableEvent);
+            if (Context.Process.HandleTable.GenerateHandle(LaunchableEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs
index 2b0b5293ed..cd3d6e4902 100644
--- a/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs
+++ b/Ryujinx.HLE/HOS/Services/Aud/AudioOut/IAudioOut.cs
@@ -67,7 +67,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
 
         public long RegisterBufferEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent);
+            if (Context.Process.HandleTable.GenerateHandle(ReleaseEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs
index ae85bf0189..85f82622f9 100644
--- a/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs
+++ b/Ryujinx.HLE/HOS/Services/Aud/AudioRenderer/IAudioRenderer.cs
@@ -72,7 +72,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
 
         private void AudioCallback()
         {
-            UpdateEvent.Signal();
+            UpdateEvent.ReadableEvent.Signal();
         }
 
         private static T[] CreateArray<T>(int Size) where T : new()
@@ -218,7 +218,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
 
         public long QuerySystemEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent);
+            if (Context.Process.HandleTable.GenerateHandle(UpdateEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs
index adecc7210a..a1a228ed1e 100644
--- a/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs
+++ b/Ryujinx.HLE/HOS/Services/Aud/IAudioDevice.cs
@@ -2,6 +2,7 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.HOS.SystemState;
 using Ryujinx.HLE.Logging;
+using System;
 using System.Collections.Generic;
 using System.Text;
 
@@ -35,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
             SystemEvent = new KEvent(System);
 
             //TODO: We shouldn't be signaling this here.
-            SystemEvent.Signal();
+            SystemEvent.ReadableEvent.Signal();
         }
 
         public long ListAudioDeviceName(ServiceCtx Context)
@@ -107,7 +108,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud
 
         public long QueryAudioDeviceSystemEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
+            if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
@@ -200,7 +204,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud
 
         public long QueryAudioDeviceInputEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
+            if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
@@ -211,7 +218,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud
 
         public long QueryAudioDeviceOutputEvent(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
+            if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs b/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs
index ef9250d926..44b856cda6 100644
--- a/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Aud/IAudioOutManager.cs
@@ -150,7 +150,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
 
             ReleaseCallback Callback = () =>
             {
-                ReleaseEvent.Signal();
+                ReleaseEvent.ReadableEvent.Signal();
             };
 
             IAalOutput AudioOut = Context.Device.AudioOut;
diff --git a/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs b/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs
index 012ccb4053..89a17acf7b 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/IAppletResource.cs
@@ -1,5 +1,6 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Hid
@@ -24,7 +25,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid
 
         public long GetSharedMemoryHandle(ServiceCtx Context)
         {
-            int Handle = Context.Process.HandleTable.OpenHandle(HidSharedMem);
+            if (Context.Process.HandleTable.GenerateHandle(HidSharedMem, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
index b42f76fa3b..e88ca7e4db 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
@@ -2,7 +2,6 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.Input;
 using Ryujinx.HLE.Logging;
-using Ryujinx.HLE.Utilities;
 using System;
 using System.Collections.Generic;
 
@@ -219,7 +218,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             long XpadId = Context.RequestData.ReadInt64();
 
-            XpadIdEventHandle = Context.Process.HandleTable.OpenHandle(XpadIdEvent);
+            if (Context.Process.HandleTable.GenerateHandle(XpadIdEvent, out XpadIdEventHandle) == 0)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(XpadIdEventHandle);
 
@@ -411,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             SixAxisSensorFusionEnabled = Context.RequestData.ReadBoolean();
             int  SixAxisSensorHandle   = Context.RequestData.ReadInt32();
             long AppletResourceUserId  = Context.RequestData.ReadInt64();
-            
+
             Context.Device.Log.PrintStub(LogClass.ServiceHid, $"Stubbed. AppletResourceUserId: {AppletResourceUserId} - " +
                                                               $"SixAxisSensorHandle: {SixAxisSensorHandle} - " +
                                                               $"SixAxisSensorFusionEnabled: {SixAxisSensorFusionEnabled}");
@@ -619,7 +621,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
 
         // IsSixAxisSensorAtRest(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsAsRest
         public long IsSixAxisSensorAtRest(ServiceCtx Context)
-        { 
+        {
             int  SixAxisSensorHandle  = Context.RequestData.ReadInt32();
             long AppletResourceUserId = Context.RequestData.ReadInt64();
 
@@ -712,7 +714,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             int  NpadId               = Context.RequestData.ReadInt32();
             long NpadStyleSet         = Context.RequestData.ReadInt64();
 
-            int Handle = Context.Process.HandleTable.OpenHandle(NpadStyleSetUpdateEvent);
+            if (Context.Process.HandleTable.GenerateHandle(NpadStyleSetUpdateEvent, out int Handle) == 0)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
@@ -1135,7 +1140,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             int  ConsoleSixAxisSensorHandle = Context.RequestData.ReadInt32();
             long AppletResourceUserId       = Context.RequestData.ReadInt64();
-            
+
             Context.Device.Log.PrintStub(LogClass.ServiceHid, $"Stubbed. AppletResourceUserId: {AppletResourceUserId} - " +
                                                               $"ConsoleSixAxisSensorHandle: {ConsoleSixAxisSensorHandle}");
 
@@ -1351,7 +1356,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid
         {
             int PalmaConnectionHandle = Context.RequestData.ReadInt32();
 
-            int Handle = Context.Process.HandleTable.OpenHandle(PalmaOperationCompleteEvent);
+            if (Context.Process.HandleTable.GenerateHandle(PalmaOperationCompleteEvent, out int Handle) == 0)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
@@ -1393,7 +1401,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
             int  PalmaConnectionHandle = Context.RequestData.ReadInt32();
             long FrModeType            = Context.RequestData.ReadInt64();
 
-            Context.Device.Log.PrintStub(LogClass.ServiceHid, $"Stubbed. PalmaConnectionHandle: {PalmaConnectionHandle} - " + 
+            Context.Device.Log.PrintStub(LogClass.ServiceHid, $"Stubbed. PalmaConnectionHandle: {PalmaConnectionHandle} - " +
                                                               $"FrModeType: {FrModeType}");
 
             return 0;
diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs
index 8e487d55c1..e9d820001d 100644
--- a/Ryujinx.HLE/HOS/Services/IpcService.cs
+++ b/Ryujinx.HLE/HOS/Services/IpcService.cs
@@ -132,7 +132,10 @@ namespace Ryujinx.HLE.HOS.Services
             {
                 KSession Session = new KSession(Obj, Context.Session.ServiceName);
 
-                int Handle = Context.Process.HandleTable.OpenHandle(Session);
+                if (Context.Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
 
                 Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
             }
@@ -146,7 +149,7 @@ namespace Ryujinx.HLE.HOS.Services
             {
                 int Handle = Context.Request.HandleDesc.ToMove[Index];
 
-                KSession Session = Context.Process.HandleTable.GetData<KSession>(Handle);
+                KSession Session = Context.Process.HandleTable.GetObject<KSession>(Handle);
 
                 return Session?.Service is T ? (T)Session.Service : null;
             }
diff --git a/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs
index 33f739677f..72a385d2ff 100644
--- a/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs
+++ b/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs
@@ -2,6 +2,7 @@
 using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.Input;
 using Ryujinx.HLE.Logging;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Nfp
@@ -55,7 +56,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfp
         {
             Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed.");
 
-            int Handle = Context.Process.HandleTable.OpenHandle(ActivateEvent);
+            if (Context.Process.HandleTable.GenerateHandle(ActivateEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);;
 
@@ -66,7 +70,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfp
         {
             Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed.");
 
-            int Handle = Context.Process.HandleTable.OpenHandle(DeactivateEvent);
+            if (Context.Process.HandleTable.GenerateHandle(DeactivateEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
@@ -104,7 +111,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfp
         {
             Context.Device.Log.PrintStub(LogClass.ServiceNfp, "Stubbed.");
 
-            int Handle = Context.Process.HandleTable.OpenHandle(AvailabilityChangeEvent);
+            if (Context.Process.HandleTable.GenerateHandle(AvailabilityChangeEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs b/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs
index 3f4df719cf..9b501d7ca7 100644
--- a/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs
+++ b/Ryujinx.HLE/HOS/Services/Nifm/IRequest.cs
@@ -1,6 +1,7 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
 using Ryujinx.HLE.Logging;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Nifm
@@ -48,8 +49,15 @@ namespace Ryujinx.HLE.HOS.Services.Nifm
 
         public long GetSystemEventReadableHandles(ServiceCtx Context)
         {
-            int Handle0 = Context.Process.HandleTable.OpenHandle(Event0);
-            int Handle1 = Context.Process.HandleTable.OpenHandle(Event1);
+            if (Context.Process.HandleTable.GenerateHandle(Event0.ReadableEvent, out int Handle0) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
+
+            if (Context.Process.HandleTable.GenerateHandle(Event1.ReadableEvent, out int Handle1) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle0, Handle1);
 
diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs
index 7d5589920f..96de8cab4e 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs
@@ -123,7 +123,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv
             int EventId = Context.RequestData.ReadInt32();
 
             //TODO: Use Fd/EventId, different channels have different events.
-            int Handle = Context.Process.HandleTable.OpenHandle(Event);
+            if (Context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs b/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs
index 92821217ba..d73adc0efd 100644
--- a/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Pl/ISharedFontManager.cs
@@ -1,5 +1,7 @@
 using Ryujinx.HLE.HOS.Font;
 using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Pl
@@ -65,7 +67,10 @@ namespace Ryujinx.HLE.HOS.Services.Pl
         {
             Context.Device.System.Font.EnsureInitialized();
 
-            int Handle = Context.Process.HandleTable.OpenHandle(Context.Device.System.FontSharedMem);
+            if (Context.Process.HandleTable.GenerateHandle(Context.Device.System.FontSharedMem, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
index c56d65dbc0..0c26b7d9dd 100644
--- a/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs
@@ -1,5 +1,6 @@
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Sm
@@ -59,7 +60,10 @@ namespace Ryujinx.HLE.HOS.Services.Sm
 
             KSession Session = new KSession(ServiceFactory.MakeService(Context.Device.System, Name), Name);
 
-            int Handle = Context.Process.HandleTable.OpenHandle(Session);
+            if (Context.Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs
index 5423827932..33a1dee974 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs
@@ -1,6 +1,8 @@
 using ChocolArm64.Memory;
 using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel;
 using System.Collections.Generic;
+using System;
 using System.IO;
 using System.Text;
 
@@ -178,7 +180,10 @@ namespace Ryujinx.HLE.HOS.Services.Vi
         {
             string Name = GetDisplayName(Context);
 
-            int Handle = Context.Process.HandleTable.OpenHandle(Context.Device.System.VsyncEvent);
+            if (Context.Process.HandleTable.GenerateHandle(Context.Device.System.VsyncEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs
index d47fc30a7d..09a37b0f7b 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/IHOSBinderDriver.cs
@@ -29,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
 
             BinderEvent = new KEvent(System);
 
-            BinderEvent.Signal();
+            BinderEvent.ReadableEvent.Signal();
 
             Flinger = new NvFlinger(Renderer, BinderEvent);
         }
@@ -77,7 +77,10 @@ namespace Ryujinx.HLE.HOS.Services.Vi
             int  Id  = Context.RequestData.ReadInt32();
             uint Unk = Context.RequestData.ReadUInt32();
 
-            int Handle = Context.Process.HandleTable.OpenHandle(BinderEvent);
+            if (Context.Process.HandleTable.GenerateHandle(BinderEvent.ReadableEvent, out int Handle) != KernelResult.Success)
+            {
+                throw new InvalidOperationException("Out of handles!");
+            }
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
 
diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
index dcdf5d1747..c5f38211b9 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
@@ -338,7 +338,7 @@ namespace Ryujinx.HLE.HOS.Services.Android
         {
             BufferQueue[Slot].State = BufferState.Free;
 
-            BinderEvent.Signal();
+            BinderEvent.ReadableEvent.Signal();
 
             WaitBufferFree.Set();
         }
diff --git a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs
index b537b06acf..274892c08a 100644
--- a/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs
+++ b/Ryujinx.HLE/HOS/SystemState/AppletStateMgr.cs
@@ -32,14 +32,14 @@ namespace Ryujinx.HLE.HOS.SystemState
         {
             Messages.Enqueue(Message);
 
-            MessageEvent.Signal();
+            MessageEvent.ReadableEvent.Signal();
         }
 
         public bool TryDequeueMessage(out MessageInfo Message)
         {
             if (Messages.Count < 2)
             {
-                MessageEvent.Reset();
+                MessageEvent.ReadableEvent.Clear();
             }
 
             return Messages.TryDequeue(out Message);