Ryujinx/Ryujinx.HLE/HOS/Kernel/KResourceLimit.cs
gdkchan 00579927e4
Better process implementation (#491)
* Initial implementation of KProcess

* Some improvements to the memory manager, implement back guest stack trace printing

* Better GetInfo implementation, improve checking in some places with information from process capabilities

* Allow the cpu to read/write from the correct memory locations for accesses crossing a page boundary

* Change long -> ulong for address/size on memory related methods to avoid unnecessary casts

* Attempt at implementing ldr:ro with new KProcess

* Allow BSS with size 0 on ldr:ro

* Add checking for memory block slab heap usage, return errors if full, exit gracefully

* Use KMemoryBlockSize const from KMemoryManager

* Allow all methods to read from non-contiguous locations

* Fix for TransactParcelAuto

* Address PR feedback, additionally fix some small issues related to the KIP loader and implement SVCs GetProcessId, GetProcessList, GetSystemInfo, CreatePort and ManageNamedPort

* Fix wrong check for source pages count from page list on MapPhysicalMemory

* Fix some issues with UnloadNro on ldr:ro
2018-11-28 20:18:09 -02:00

146 lines
3.9 KiB
C#

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;
}
}
}