KResourceLimit.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 object _lock;
  13. private readonly LinkedList<KThread> _waitingThreads;
  14. private int _waitingThreadsCount;
  15. public KResourceLimit(KernelContext context) : base(context)
  16. {
  17. _current = new long[(int)LimitableResource.Count];
  18. _limit = new long[(int)LimitableResource.Count];
  19. _current2 = new long[(int)LimitableResource.Count];
  20. _lock = new object();
  21. _waitingThreads = new LinkedList<KThread>();
  22. }
  23. public bool Reserve(LimitableResource resource, ulong amount)
  24. {
  25. return Reserve(resource, (long)amount);
  26. }
  27. public bool Reserve(LimitableResource resource, long amount)
  28. {
  29. return Reserve(resource, amount, KTimeManager.ConvertMillisecondsToNanoseconds(DefaultTimeoutMs));
  30. }
  31. public bool Reserve(LimitableResource resource, long amount, long timeout)
  32. {
  33. long endTimePoint = KTimeManager.ConvertNanosecondsToMilliseconds(timeout);
  34. endTimePoint += PerformanceCounter.ElapsedMilliseconds;
  35. bool success = false;
  36. int index = GetIndex(resource);
  37. lock (_lock)
  38. {
  39. if (_current2[index] >= _limit[index])
  40. {
  41. return false;
  42. }
  43. long newCurrent = _current[index] + amount;
  44. while (newCurrent > _limit[index] && _current2[index] + amount <= _limit[index])
  45. {
  46. _waitingThreadsCount++;
  47. KConditionVariable.Wait(KernelContext, _waitingThreads, _lock, timeout);
  48. _waitingThreadsCount--;
  49. newCurrent = _current[index] + amount;
  50. if (timeout >= 0 && PerformanceCounter.ElapsedMilliseconds > endTimePoint)
  51. {
  52. break;
  53. }
  54. }
  55. if (newCurrent <= _limit[index])
  56. {
  57. _current[index] = newCurrent;
  58. _current2[index] += amount;
  59. success = true;
  60. }
  61. }
  62. return success;
  63. }
  64. public void Release(LimitableResource resource, ulong amount)
  65. {
  66. Release(resource, (long)amount);
  67. }
  68. public void Release(LimitableResource resource, long amount)
  69. {
  70. Release(resource, amount, amount);
  71. }
  72. public void Release(LimitableResource resource, long amount, long amount2)
  73. {
  74. int index = GetIndex(resource);
  75. lock (_lock)
  76. {
  77. _current[index] -= amount;
  78. _current2[index] -= amount2;
  79. if (_waitingThreadsCount > 0)
  80. {
  81. KConditionVariable.NotifyAll(KernelContext, _waitingThreads);
  82. }
  83. }
  84. }
  85. public long GetRemainingValue(LimitableResource resource)
  86. {
  87. int index = GetIndex(resource);
  88. lock (_lock)
  89. {
  90. return _limit[index] - _current[index];
  91. }
  92. }
  93. public KernelResult SetLimitValue(LimitableResource resource, long limit)
  94. {
  95. int index = GetIndex(resource);
  96. lock (_lock)
  97. {
  98. if (_current[index] <= limit)
  99. {
  100. _limit[index] = limit;
  101. return KernelResult.Success;
  102. }
  103. else
  104. {
  105. return KernelResult.InvalidState;
  106. }
  107. }
  108. }
  109. private static int GetIndex(LimitableResource resource)
  110. {
  111. return (int)resource;
  112. }
  113. }
  114. }