/ src / Ryujinx.HLE / HOS / Kernel / Process / KHandleTable.cs
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  }