diff options
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/KResourceLimit.cs')
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/KResourceLimit.cs | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/KResourceLimit.cs b/Ryujinx.HLE/HOS/Kernel/KResourceLimit.cs new file mode 100644 index 00000000..6fd70d0c --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/KResourceLimit.cs @@ -0,0 +1,146 @@ +using Ryujinx.Common; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Kernel +{ + class KResourceLimit + { + private const int Time10SecondsMs = 10000; + + private long[] Current; + private long[] Limit; + private long[] Available; + + private object LockObj; + + private LinkedList<KThread> WaitingThreads; + + private int WaitingThreadsCount; + + private Horizon System; + + public KResourceLimit(Horizon System) + { + Current = new long[(int)LimitableResource.Count]; + Limit = new long[(int)LimitableResource.Count]; + Available = new long[(int)LimitableResource.Count]; + + LockObj = new object(); + + WaitingThreads = new LinkedList<KThread>(); + + this.System = System; + } + + 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(Time10SecondsMs)); + } + + 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 (LockObj) + { + long NewCurrent = Current[Index] + Amount; + + while (NewCurrent > Limit[Index] && Available[Index] + Amount <= Limit[Index]) + { + WaitingThreadsCount++; + + KConditionVariable.Wait(System, WaitingThreads, LockObj, Timeout); + + WaitingThreadsCount--; + + NewCurrent = Current[Index] + Amount; + + if (Timeout >= 0 && PerformanceCounter.ElapsedMilliseconds > EndTimePoint) + { + break; + } + } + + if (NewCurrent <= Limit[Index]) + { + Current[Index] = NewCurrent; + + 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); + } + + private void Release(LimitableResource Resource, long UsedAmount, long AvailableAmount) + { + int Index = GetIndex(Resource); + + lock (LockObj) + { + Current [Index] -= UsedAmount; + Available[Index] -= AvailableAmount; + + if (WaitingThreadsCount > 0) + { + KConditionVariable.NotifyAll(System, WaitingThreads); + } + } + } + + public long GetRemainingValue(LimitableResource Resource) + { + int Index = GetIndex(Resource); + + lock (LockObj) + { + return Limit[Index] - Current[Index]; + } + } + + public KernelResult SetLimitValue(LimitableResource Resource, long Limit) + { + int Index = GetIndex(Resource); + + lock (LockObj) + { + if (Current[Index] <= Limit) + { + this.Limit[Index] = Limit; + + return KernelResult.Success; + } + else + { + return KernelResult.InvalidState; + } + } + } + + private static int GetIndex(LimitableResource Resource) + { + return (int)Resource; + } + } +}
\ No newline at end of file |
