aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs')
-rw-r--r--src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs b/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
new file mode 100644
index 00000000..b1a602f1
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs
@@ -0,0 +1,188 @@
+using Ryujinx.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.Horizon.Common;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Kernel.Common
+{
+ class KResourceLimit : KAutoObject
+ {
+ private const int DefaultTimeoutMs = 10000; // 10s
+
+ private readonly long[] _current;
+ private readonly long[] _limit;
+ private readonly long[] _current2;
+ private readonly long[] _peak;
+
+ private readonly object _lock;
+
+ private readonly LinkedList<KThread> _waitingThreads;
+
+ private int _waitingThreadsCount;
+
+ public KResourceLimit(KernelContext context) : base(context)
+ {
+ _current = new long[(int)LimitableResource.Count];
+ _limit = new long[(int)LimitableResource.Count];
+ _current2 = new long[(int)LimitableResource.Count];
+ _peak = new long[(int)LimitableResource.Count];
+
+ _lock = new object();
+
+ _waitingThreads = new LinkedList<KThread>();
+ }
+
+ public bool Reserve(LimitableResource resource, ulong amount)
+ {
+ return Reserve(resource, (long)amount);
+ }
+
+ public bool Reserve(LimitableResource resource, long amount)
+ {
+ return Reserve(resource, amount, KTimeManager.ConvertMillisecondsToNanoseconds(DefaultTimeoutMs));
+ }
+
+ public bool Reserve(LimitableResource resource, long amount, long timeout)
+ {
+ long endTimePoint = KTimeManager.ConvertNanosecondsToMilliseconds(timeout);
+
+ endTimePoint += PerformanceCounter.ElapsedMilliseconds;
+
+ bool success = false;
+
+ int index = GetIndex(resource);
+
+ lock (_lock)
+ {
+ if (_current2[index] >= _limit[index])
+ {
+ return false;
+ }
+
+ long newCurrent = _current[index] + amount;
+
+ while (newCurrent > _limit[index] && _current2[index] + amount <= _limit[index])
+ {
+ _waitingThreadsCount++;
+
+ KConditionVariable.Wait(KernelContext, _waitingThreads, _lock, timeout);
+
+ _waitingThreadsCount--;
+
+ newCurrent = _current[index] + amount;
+
+ if (timeout >= 0 && PerformanceCounter.ElapsedMilliseconds > endTimePoint)
+ {
+ break;
+ }
+ }
+
+ if (newCurrent <= _limit[index])
+ {
+ _current[index] = newCurrent;
+ _current2[index] += amount;
+
+ if (_current[index] > _peak[index])
+ {
+ _peak[index] = _current[index];
+ }
+
+ success = true;
+ }
+ }
+
+ return success;
+ }
+
+ public void Release(LimitableResource resource, ulong amount)
+ {
+ Release(resource, (long)amount);
+ }
+
+ public void Release(LimitableResource resource, long amount)
+ {
+ Release(resource, amount, amount);
+ }
+
+ public void Release(LimitableResource resource, long amount, long amount2)
+ {
+ int index = GetIndex(resource);
+
+ lock (_lock)
+ {
+ _current[index] -= amount;
+ _current2[index] -= amount2;
+
+ if (_waitingThreadsCount > 0)
+ {
+ KConditionVariable.NotifyAll(KernelContext, _waitingThreads);
+ }
+ }
+ }
+
+ public long GetRemainingValue(LimitableResource resource)
+ {
+ int index = GetIndex(resource);
+
+ lock (_lock)
+ {
+ return _limit[index] - _current[index];
+ }
+ }
+
+ public long GetCurrentValue(LimitableResource resource)
+ {
+ int index = GetIndex(resource);
+
+ lock (_lock)
+ {
+ return _current[index];
+ }
+ }
+
+ public long GetLimitValue(LimitableResource resource)
+ {
+ int index = GetIndex(resource);
+
+ lock (_lock)
+ {
+ return _limit[index];
+ }
+ }
+
+ public long GetPeakValue(LimitableResource resource)
+ {
+ int index = GetIndex(resource);
+
+ lock (_lock)
+ {
+ return _peak[index];
+ }
+ }
+
+ public Result SetLimitValue(LimitableResource resource, long limit)
+ {
+ int index = GetIndex(resource);
+
+ lock (_lock)
+ {
+ if (_current[index] <= limit)
+ {
+ _limit[index] = limit;
+ _peak[index] = _current[index];
+
+ return Result.Success;
+ }
+ else
+ {
+ return KernelResult.InvalidState;
+ }
+ }
+ }
+
+ private static int GetIndex(LimitableResource resource)
+ {
+ return (int)resource;
+ }
+ }
+} \ No newline at end of file