ServerDomainManager.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. using Ryujinx.Horizon.Common;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Threading;
  5. namespace Ryujinx.Horizon.Sdk.Sf.Cmif
  6. {
  7. class ServerDomainManager
  8. {
  9. private class EntryManager
  10. {
  11. public class Entry
  12. {
  13. public int Id { get; }
  14. public Domain Owner { get; set; }
  15. public ServiceObjectHolder Obj { get; set; }
  16. public LinkedListNode<Entry> Node { get; set; }
  17. public Entry(int id)
  18. {
  19. Id = id;
  20. }
  21. }
  22. private readonly LinkedList<Entry> _freeList;
  23. private readonly Entry[] _entries;
  24. public EntryManager(int count)
  25. {
  26. _freeList = [];
  27. _entries = new Entry[count];
  28. for (int i = 0; i < count; i++)
  29. {
  30. _freeList.AddLast(_entries[i] = new Entry(i + 1));
  31. }
  32. }
  33. public Entry AllocateEntry()
  34. {
  35. lock (_freeList)
  36. {
  37. if (_freeList.Count == 0)
  38. {
  39. return null;
  40. }
  41. Entry entry = _freeList.First.Value;
  42. _freeList.RemoveFirst();
  43. return entry;
  44. }
  45. }
  46. public void FreeEntry(Entry entry)
  47. {
  48. lock (_freeList)
  49. {
  50. DebugUtil.Assert(entry.Owner == null);
  51. DebugUtil.Assert(entry.Obj == null);
  52. _freeList.AddFirst(entry);
  53. }
  54. }
  55. public Entry GetEntry(int id)
  56. {
  57. if (id == 0)
  58. {
  59. return null;
  60. }
  61. int index = id - 1;
  62. if ((uint)index >= (uint)_entries.Length)
  63. {
  64. return null;
  65. }
  66. return _entries[index];
  67. }
  68. }
  69. private class Domain : DomainServiceObject, IDisposable
  70. {
  71. private readonly ServerDomainManager _manager;
  72. private readonly LinkedList<EntryManager.Entry> _entries;
  73. public Domain(ServerDomainManager manager)
  74. {
  75. _manager = manager;
  76. _entries = [];
  77. }
  78. public override ServiceObjectHolder GetObject(int id)
  79. {
  80. EntryManager.Entry entry = _manager._entryManager.GetEntry(id);
  81. if (entry == null)
  82. {
  83. return null;
  84. }
  85. lock (_manager._entryOwnerLock)
  86. {
  87. if (entry.Owner != this)
  88. {
  89. return null;
  90. }
  91. }
  92. return entry.Obj.Clone();
  93. }
  94. public override ServerDomainBase GetServerDomain()
  95. {
  96. return this;
  97. }
  98. public override void RegisterObject(int id, ServiceObjectHolder obj)
  99. {
  100. EntryManager.Entry entry = _manager._entryManager.GetEntry(id);
  101. DebugUtil.Assert(entry != null);
  102. lock (_manager._entryOwnerLock)
  103. {
  104. DebugUtil.Assert(entry.Owner == null);
  105. entry.Owner = this;
  106. entry.Node = _entries.AddLast(entry);
  107. }
  108. entry.Obj = obj;
  109. }
  110. public override Result ReserveIds(Span<int> outIds)
  111. {
  112. for (int i = 0; i < outIds.Length; i++)
  113. {
  114. EntryManager.Entry entry = _manager._entryManager.AllocateEntry();
  115. if (entry == null)
  116. {
  117. return SfResult.OutOfDomainEntries;
  118. }
  119. DebugUtil.Assert(entry.Owner == null);
  120. outIds[i] = entry.Id;
  121. }
  122. return Result.Success;
  123. }
  124. public override ServiceObjectHolder UnregisterObject(int id)
  125. {
  126. EntryManager.Entry entry = _manager._entryManager.GetEntry(id);
  127. if (entry == null)
  128. {
  129. return null;
  130. }
  131. ServiceObjectHolder obj;
  132. lock (_manager._entryOwnerLock)
  133. {
  134. if (entry.Owner != this)
  135. {
  136. return null;
  137. }
  138. entry.Owner = null;
  139. obj = entry.Obj;
  140. if (obj.ServiceObject is IDisposable disposableObj)
  141. {
  142. disposableObj.Dispose();
  143. }
  144. entry.Obj = null;
  145. _entries.Remove(entry.Node);
  146. entry.Node = null;
  147. }
  148. _manager._entryManager.FreeEntry(entry);
  149. return obj;
  150. }
  151. public override void UnreserveIds(ReadOnlySpan<int> ids)
  152. {
  153. for (int i = 0; i < ids.Length; i++)
  154. {
  155. EntryManager.Entry entry = _manager._entryManager.GetEntry(ids[i]);
  156. DebugUtil.Assert(entry != null);
  157. DebugUtil.Assert(entry.Owner == null);
  158. _manager._entryManager.FreeEntry(entry);
  159. }
  160. }
  161. public void Dispose()
  162. {
  163. foreach (EntryManager.Entry entry in _entries)
  164. {
  165. if (entry.Obj.ServiceObject is IDisposable disposableObj)
  166. {
  167. disposableObj.Dispose();
  168. }
  169. }
  170. _manager.FreeDomain(this);
  171. }
  172. }
  173. private readonly EntryManager _entryManager;
  174. private readonly Lock _entryOwnerLock = new();
  175. private readonly HashSet<Domain> _domains;
  176. private readonly int _maxDomains;
  177. public ServerDomainManager(int entryCount, int maxDomains)
  178. {
  179. _entryManager = new EntryManager(entryCount);
  180. _domains = [];
  181. _maxDomains = maxDomains;
  182. }
  183. public DomainServiceObject AllocateDomainServiceObject()
  184. {
  185. lock (_domains)
  186. {
  187. if (_domains.Count == _maxDomains)
  188. {
  189. return null;
  190. }
  191. Domain domain = new(this);
  192. _domains.Add(domain);
  193. return domain;
  194. }
  195. }
  196. public static void DestroyDomainServiceObject(DomainServiceObject obj)
  197. {
  198. ((Domain)obj).Dispose();
  199. }
  200. private void FreeDomain(Domain domain)
  201. {
  202. lock (_domains)
  203. {
  204. _domains.Remove(domain);
  205. }
  206. }
  207. }
  208. }