KResourceLimit.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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
  7. {
  8. private const int Time10SecondsMs = 10000;
  9. private long[] _current;
  10. private long[] _limit;
  11. private long[] _available;
  12. private object _lockObj;
  13. private LinkedList<KThread> _waitingThreads;
  14. private int _waitingThreadsCount;
  15. private Horizon _system;
  16. public KResourceLimit(Horizon system)
  17. {
  18. _current = new long[(int)LimitableResource.Count];
  19. _limit = new long[(int)LimitableResource.Count];
  20. _available = new long[(int)LimitableResource.Count];
  21. _lockObj = new object();
  22. _waitingThreads = new LinkedList<KThread>();
  23. _system = system;
  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(Time10SecondsMs));
  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 (_lockObj)
  40. {
  41. long newCurrent = _current[index] + amount;
  42. while (newCurrent > _limit[index] && _available[index] + amount <= _limit[index])
  43. {
  44. _waitingThreadsCount++;
  45. KConditionVariable.Wait(_system, _waitingThreads, _lockObj, timeout);
  46. _waitingThreadsCount--;
  47. newCurrent = _current[index] + amount;
  48. if (timeout >= 0 && PerformanceCounter.ElapsedMilliseconds > endTimePoint)
  49. {
  50. break;
  51. }
  52. }
  53. if (newCurrent <= _limit[index])
  54. {
  55. _current[index] = newCurrent;
  56. success = true;
  57. }
  58. }
  59. return success;
  60. }
  61. public void Release(LimitableResource resource, ulong amount)
  62. {
  63. Release(resource, (long)amount);
  64. }
  65. public void Release(LimitableResource resource, long amount)
  66. {
  67. Release(resource, amount, amount);
  68. }
  69. private void Release(LimitableResource resource, long usedAmount, long availableAmount)
  70. {
  71. int index = GetIndex(resource);
  72. lock (_lockObj)
  73. {
  74. _current [index] -= usedAmount;
  75. _available[index] -= availableAmount;
  76. if (_waitingThreadsCount > 0)
  77. {
  78. KConditionVariable.NotifyAll(_system, _waitingThreads);
  79. }
  80. }
  81. }
  82. public long GetRemainingValue(LimitableResource resource)
  83. {
  84. int index = GetIndex(resource);
  85. lock (_lockObj)
  86. {
  87. return _limit[index] - _current[index];
  88. }
  89. }
  90. public KernelResult SetLimitValue(LimitableResource resource, long limit)
  91. {
  92. int index = GetIndex(resource);
  93. lock (_lockObj)
  94. {
  95. if (_current[index] <= limit)
  96. {
  97. _limit[index] = limit;
  98. return KernelResult.Success;
  99. }
  100. else
  101. {
  102. return KernelResult.InvalidState;
  103. }
  104. }
  105. }
  106. private static int GetIndex(LimitableResource resource)
  107. {
  108. return (int)resource;
  109. }
  110. }
  111. }