KHandleTable.cs
1 using Ryujinx.HLE.HOS.Kernel.Common; 2 using Ryujinx.HLE.HOS.Kernel.Threading; 3 using Ryujinx.Horizon.Common; 4 using System; 5 6 namespace Ryujinx.HLE.HOS.Kernel.Process 7 { 8 class KHandleTable 9 { 10 public const int SelfThreadHandle = (0x1ffff << 15) | 0; 11 public const int SelfProcessHandle = (0x1ffff << 15) | 1; 12 13 private KHandleEntry[] _table; 14 15 private KHandleEntry _tableHead; 16 private KHandleEntry _nextFreeEntry; 17 18 private int _activeSlotsCount; 19 20 private uint _size; 21 22 private ushort _idCounter; 23 24 public Result Initialize(uint size) 25 { 26 if (size > 1024) 27 { 28 return KernelResult.OutOfMemory; 29 } 30 31 if (size < 1) 32 { 33 size = 1024; 34 } 35 36 _size = size; 37 38 _idCounter = 1; 39 40 _table = new KHandleEntry[size]; 41 42 _tableHead = new KHandleEntry(0); 43 44 KHandleEntry entry = _tableHead; 45 46 for (int index = 0; index < size; index++) 47 { 48 _table[index] = entry; 49 50 entry.Next = new KHandleEntry(index + 1); 51 52 entry = entry.Next; 53 } 54 55 _table[size - 1].Next = null; 56 57 _nextFreeEntry = _tableHead; 58 59 return Result.Success; 60 } 61 62 public Result GenerateHandle(KAutoObject obj, out int handle) 63 { 64 handle = 0; 65 66 lock (_table) 67 { 68 if (_activeSlotsCount >= _size) 69 { 70 return KernelResult.HandleTableFull; 71 } 72 73 KHandleEntry entry = _nextFreeEntry; 74 75 _nextFreeEntry = entry.Next; 76 77 entry.Obj = obj; 78 entry.HandleId = _idCounter; 79 80 _activeSlotsCount++; 81 82 handle = (_idCounter << 15) | entry.Index; 83 84 obj.IncrementReferenceCount(); 85 86 if ((short)(_idCounter + 1) >= 0) 87 { 88 _idCounter++; 89 } 90 else 91 { 92 _idCounter = 1; 93 } 94 } 95 96 return Result.Success; 97 } 98 99 public Result ReserveHandle(out int handle) 100 { 101 handle = 0; 102 103 lock (_table) 104 { 105 if (_activeSlotsCount >= _size) 106 { 107 return KernelResult.HandleTableFull; 108 } 109 110 KHandleEntry entry = _nextFreeEntry; 111 112 _nextFreeEntry = entry.Next; 113 114 _activeSlotsCount++; 115 116 handle = (_idCounter << 15) | entry.Index; 117 118 if ((short)(_idCounter + 1) >= 0) 119 { 120 _idCounter++; 121 } 122 else 123 { 124 _idCounter = 1; 125 } 126 } 127 128 return Result.Success; 129 } 130 131 public void CancelHandleReservation(int handle) 132 { 133 int index = handle & 0x7fff; 134 135 lock (_table) 136 { 137 KHandleEntry entry = _table[index]; 138 139 entry.Obj = null; 140 entry.Next = _nextFreeEntry; 141 142 _nextFreeEntry = entry; 143 144 _activeSlotsCount--; 145 } 146 } 147 148 public void SetReservedHandleObj(int handle, KAutoObject obj) 149 { 150 int index = (handle >> 0) & 0x7fff; 151 int handleId = (handle >> 15); 152 153 lock (_table) 154 { 155 KHandleEntry entry = _table[index]; 156 157 entry.Obj = obj; 158 entry.HandleId = (ushort)handleId; 159 160 obj.IncrementReferenceCount(); 161 } 162 } 163 164 public bool CloseHandle(int handle) 165 { 166 if ((handle >> 30) != 0 || 167 handle == SelfThreadHandle || 168 handle == SelfProcessHandle) 169 { 170 return false; 171 } 172 173 int index = (handle >> 0) & 0x7fff; 174 int handleId = (handle >> 15); 175 176 KAutoObject obj = null; 177 178 bool result = false; 179 180 lock (_table) 181 { 182 if (handleId != 0 && index < _size) 183 { 184 KHandleEntry entry = _table[index]; 185 186 if ((obj = entry.Obj) != null && entry.HandleId == handleId) 187 { 188 entry.Obj = null; 189 entry.Next = _nextFreeEntry; 190 191 _nextFreeEntry = entry; 192 193 _activeSlotsCount--; 194 195 result = true; 196 } 197 } 198 } 199 200 if (result) 201 { 202 obj.DecrementReferenceCount(); 203 } 204 205 return result; 206 } 207 208 public T GetObject<T>(int handle) where T : KAutoObject 209 { 210 int index = (handle >> 0) & 0x7fff; 211 int handleId = (handle >> 15); 212 213 lock (_table) 214 { 215 if ((handle >> 30) == 0 && handleId != 0 && index < _size) 216 { 217 KHandleEntry entry = _table[index]; 218 219 if (entry.HandleId == handleId && entry.Obj is T obj) 220 { 221 return obj; 222 } 223 } 224 } 225 226 return default; 227 } 228 229 public KThread GetKThread(int handle) 230 { 231 if (handle == SelfThreadHandle) 232 { 233 return KernelStatic.GetCurrentThread(); 234 } 235 else 236 { 237 return GetObject<KThread>(handle); 238 } 239 } 240 241 public KProcess GetKProcess(int handle) 242 { 243 if (handle == SelfProcessHandle) 244 { 245 return KernelStatic.GetCurrentProcess(); 246 } 247 else 248 { 249 return GetObject<KProcess>(handle); 250 } 251 } 252 253 public void Destroy() 254 { 255 lock (_table) 256 { 257 for (int index = 0; index < _size; index++) 258 { 259 KHandleEntry entry = _table[index]; 260 261 if (entry.Obj != null) 262 { 263 if (entry.Obj is IDisposable disposableObj) 264 { 265 disposableObj.Dispose(); 266 } 267 268 entry.Obj.DecrementReferenceCount(); 269 entry.Obj = null; 270 entry.Next = _nextFreeEntry; 271 272 _nextFreeEntry = entry; 273 } 274 } 275 } 276 } 277 } 278 }