KResourceLimit.cs 4.0 KB

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