KResourceLimit.cs 5.1 KB

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