KResourceLimit.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using Ryujinx.Common;
  2. using Ryujinx.HLE.HOS.Kernel.Threading;
  3. using System.Collections.Generic;
  4. namespace Ryujinx.HLE.HOS.Kernel.Common
  5. {
  6. class KResourceLimit : KAutoObject
  7. {
  8. private const int DefaultTimeoutMs = 10000; // 10s
  9. private readonly long[] _current;
  10. private readonly long[] _limit;
  11. private readonly long[] _current2;
  12. private readonly long[] _peak;
  13. private readonly object _lock;
  14. private readonly LinkedList<KThread> _waitingThreads;
  15. private int _waitingThreadsCount;
  16. public KResourceLimit(KernelContext context) : base(context)
  17. {
  18. _current = new long[(int)LimitableResource.Count];
  19. _limit = new long[(int)LimitableResource.Count];
  20. _current2 = new long[(int)LimitableResource.Count];
  21. _peak = new long[(int)LimitableResource.Count];
  22. _lock = new object();
  23. _waitingThreads = new LinkedList<KThread>();
  24. }
  25. public bool Reserve(LimitableResource resource, ulong amount)
  26. {
  27. return Reserve(resource, (long)amount);
  28. }
  29. public bool Reserve(LimitableResource resource, long amount)
  30. {
  31. return Reserve(resource, amount, KTimeManager.ConvertMillisecondsToNanoseconds(DefaultTimeoutMs));
  32. }
  33. public bool Reserve(LimitableResource resource, long amount, long timeout)
  34. {
  35. long endTimePoint = KTimeManager.ConvertNanosecondsToMilliseconds(timeout);
  36. endTimePoint += PerformanceCounter.ElapsedMilliseconds;
  37. bool success = false;
  38. int index = GetIndex(resource);
  39. lock (_lock)
  40. {
  41. if (_current2[index] >= _limit[index])
  42. {
  43. return false;
  44. }
  45. long newCurrent = _current[index] + amount;
  46. while (newCurrent > _limit[index] && _current2[index] + amount <= _limit[index])
  47. {
  48. _waitingThreadsCount++;
  49. KConditionVariable.Wait(KernelContext, _waitingThreads, _lock, timeout);
  50. _waitingThreadsCount--;
  51. newCurrent = _current[index] + amount;
  52. if (timeout >= 0 && PerformanceCounter.ElapsedMilliseconds > endTimePoint)
  53. {
  54. break;
  55. }
  56. }
  57. if (newCurrent <= _limit[index])
  58. {
  59. _current[index] = newCurrent;
  60. _current2[index] += amount;
  61. if (_current[index] > _peak[index])
  62. {
  63. _peak[index] = _current[index];
  64. }
  65. success = true;
  66. }
  67. }
  68. return success;
  69. }
  70. public void Release(LimitableResource resource, ulong amount)
  71. {
  72. Release(resource, (long)amount);
  73. }
  74. public void Release(LimitableResource resource, long amount)
  75. {
  76. Release(resource, amount, amount);
  77. }
  78. public void Release(LimitableResource resource, long amount, long amount2)
  79. {
  80. int index = GetIndex(resource);
  81. lock (_lock)
  82. {
  83. _current[index] -= amount;
  84. _current2[index] -= amount2;
  85. if (_waitingThreadsCount > 0)
  86. {
  87. KConditionVariable.NotifyAll(KernelContext, _waitingThreads);
  88. }
  89. }
  90. }
  91. public long GetRemainingValue(LimitableResource resource)
  92. {
  93. int index = GetIndex(resource);
  94. lock (_lock)
  95. {
  96. return _limit[index] - _current[index];
  97. }
  98. }
  99. public long GetCurrentValue(LimitableResource resource)
  100. {
  101. int index = GetIndex(resource);
  102. lock (_lock)
  103. {
  104. return _current[index];
  105. }
  106. }
  107. public long GetLimitValue(LimitableResource resource)
  108. {
  109. int index = GetIndex(resource);
  110. lock (_lock)
  111. {
  112. return _limit[index];
  113. }
  114. }
  115. public long GetPeakValue(LimitableResource resource)
  116. {
  117. int index = GetIndex(resource);
  118. lock (_lock)
  119. {
  120. return _peak[index];
  121. }
  122. }
  123. public KernelResult SetLimitValue(LimitableResource resource, long limit)
  124. {
  125. int index = GetIndex(resource);
  126. lock (_lock)
  127. {
  128. if (_current[index] <= limit)
  129. {
  130. _limit[index] = limit;
  131. _peak[index] = _current[index];
  132. return KernelResult.Success;
  133. }
  134. else
  135. {
  136. return KernelResult.InvalidState;
  137. }
  138. }
  139. }
  140. private static int GetIndex(LimitableResource resource)
  141. {
  142. return (int)resource;
  143. }
  144. }
  145. }