From 46f8cef6a9e4a305803f1356446e25ce54909130 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 17 Jul 2020 01:18:31 -0300 Subject: [PATCH] Fix resource limit reserve taking too long (#1391) --- .../HOS/Kernel/Common/KResourceLimit.cs | 40 +++++++++------- .../HOS/Kernel/Memory/KMemoryManager.cs | 47 +++++++++---------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs b/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs index 91501a9889..64b964da44 100644 --- a/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs +++ b/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs @@ -6,13 +6,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Common { class KResourceLimit : KAutoObject { - private const int Time10SecondsMs = 10000; + private const int DefaultTimeoutMs = 10000; // 10s private readonly long[] _current; private readonly long[] _limit; - private readonly long[] _available; + private readonly long[] _current2; - private readonly object _lockObj; + private readonly object _lock; private readonly LinkedList _waitingThreads; @@ -20,11 +20,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Common public KResourceLimit(KernelContext context) : base(context) { - _current = new long[(int)LimitableResource.Count]; - _limit = new long[(int)LimitableResource.Count]; - _available = new long[(int)LimitableResource.Count]; + _current = new long[(int)LimitableResource.Count]; + _limit = new long[(int)LimitableResource.Count]; + _current2 = new long[(int)LimitableResource.Count]; - _lockObj = new object(); + _lock = new object(); _waitingThreads = new LinkedList(); } @@ -36,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common public bool Reserve(LimitableResource resource, long amount) { - return Reserve(resource, amount, KTimeManager.ConvertMillisecondsToNanoseconds(Time10SecondsMs)); + return Reserve(resource, amount, KTimeManager.ConvertMillisecondsToNanoseconds(DefaultTimeoutMs)); } public bool Reserve(LimitableResource resource, long amount, long timeout) @@ -49,15 +49,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Common int index = GetIndex(resource); - lock (_lockObj) + lock (_lock) { + if (_current2[index] >= _limit[index]) + { + return false; + } + long newCurrent = _current[index] + amount; - while (newCurrent > _limit[index] && _available[index] + amount <= _limit[index]) + while (newCurrent > _limit[index] && _current2[index] + amount <= _limit[index]) { _waitingThreadsCount++; - KConditionVariable.Wait(KernelContext, _waitingThreads, _lockObj, timeout); + KConditionVariable.Wait(KernelContext, _waitingThreads, _lock, timeout); _waitingThreadsCount--; @@ -72,6 +77,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common if (newCurrent <= _limit[index]) { _current[index] = newCurrent; + _current2[index] += amount; success = true; } @@ -90,14 +96,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Common Release(resource, amount, amount); } - public void Release(LimitableResource resource, long usedAmount, long availableAmount) + public void Release(LimitableResource resource, long amount, long amount2) { int index = GetIndex(resource); - lock (_lockObj) + lock (_lock) { - _current [index] -= usedAmount; - _available[index] -= availableAmount; + _current[index] -= amount; + _current2[index] -= amount2; if (_waitingThreadsCount > 0) { @@ -110,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common { int index = GetIndex(resource); - lock (_lockObj) + lock (_lock) { return _limit[index] - _current[index]; } @@ -120,7 +126,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common { int index = GetIndex(resource); - lock (_lockObj) + lock (_lock) { if (_current[index] <= limit) { diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs index c7b95fbf0c..1cbe4e7c1a 100644 --- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs @@ -729,22 +729,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); - ulong currentHeapSize = GetHeapSize(); - - if (currentHeapSize <= size) + lock (_blocks) { - // Expand. - ulong diffSize = size - currentHeapSize; + ulong currentHeapSize = GetHeapSize(); - lock (_blocks) + if (currentHeapSize <= size) { - if (currentProcess.ResourceLimit != null && diffSize != 0 && - !currentProcess.ResourceLimit.Reserve(LimitableResource.Memory, diffSize)) + // Expand. + ulong sizeDelta = size - currentHeapSize; + + if (currentProcess.ResourceLimit != null && sizeDelta != 0 && + !currentProcess.ResourceLimit.Reserve(LimitableResource.Memory, sizeDelta)) { return KernelResult.ResLimitExceeded; } - ulong pagesCount = diffSize / PageSize; + ulong pagesCount = sizeDelta / PageSize; KMemoryRegionManager region = GetMemoryRegionManager(); @@ -757,9 +757,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory region.FreePages(pageList); } - if (currentProcess.ResourceLimit != null && diffSize != 0) + if (currentProcess.ResourceLimit != null && sizeDelta != 0) { - currentProcess.ResourceLimit.Release(LimitableResource.Memory, diffSize); + currentProcess.ResourceLimit.Release(LimitableResource.Memory, sizeDelta); } } @@ -777,7 +777,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.OutOfResource; } - if (!IsUnmapped(_currentHeapAddr, diffSize)) + if (!IsUnmapped(_currentHeapAddr, sizeDelta)) { CleanUpForError(); @@ -800,15 +800,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite); } - } - else - { - // Shrink. - ulong freeAddr = HeapRegionStart + size; - ulong diffSize = currentHeapSize - size; - - lock (_blocks) + else { + // Shrink. + ulong freeAddr = HeapRegionStart + size; + ulong sizeDelta = currentHeapSize - size; + if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion)) { return KernelResult.OutOfResource; @@ -816,7 +813,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory if (!CheckRange( freeAddr, - diffSize, + sizeDelta, MemoryState.Mask, MemoryState.Heap, MemoryPermission.Mask, @@ -831,7 +828,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.InvalidMemState; } - ulong pagesCount = diffSize / PageSize; + ulong pagesCount = sizeDelta / PageSize; KernelResult result = MmuUnmap(freeAddr, pagesCount); @@ -840,13 +837,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return result; } - currentProcess.ResourceLimit?.Release(LimitableResource.Memory, BitUtils.AlignDown(diffSize, PageSize)); + currentProcess.ResourceLimit?.Release(LimitableResource.Memory, sizeDelta); InsertBlock(freeAddr, pagesCount, MemoryState.Unmapped); } - } - _currentHeapAddr = HeapRegionStart + size; + _currentHeapAddr = HeapRegionStart + size; + } address = HeapRegionStart;