From 7de7b559adc1924d3ff31cc58b281f70e468155f Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sun, 23 Sep 2018 15:11:46 -0300
Subject: Improve kernel events implementation (#430)

* Improve kernel events implementation

* Some cleanup

* Address PR feedback
---
 Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs | 173 ++++++++++++++++++++++++--
 1 file changed, 161 insertions(+), 12 deletions(-)

(limited to 'Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs')

diff --git a/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs b/Ryujinx.HLE/HOS/Kernel/KProcessHandleTable.cs
index db0eaa44..682f08d4 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 KernelResult GenerateHandle(object Obj, out int Handle)
+        {
+            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 int OpenHandle(object Obj)
+        public bool CloseHandle(int Handle)
         {
-            return Handles.Add(Obj);
+            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 T GetData<T>(int Handle)
+        public T GetObject<T>(int Handle)
         {
-            return Handles.GetData<T>(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 object CloseHandle(int Handle)
+        public KThread GetKThread(int Handle)
         {
-            return Handles.Delete(Handle);
+            if (Handle == SelfThreadHandle)
+            {
+                return System.Scheduler.GetCurrentThread();
+            }
+            else
+            {
+                return GetObject<KThread>(Handle);
+            }
         }
 
-        public ICollection<object> Clear()
+        public void Destroy()
         {
-            return Handles.Clear();
+            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
-- 
cgit v1.2.3-70-g09d2