Просмотр исходного кода

Fix resource limit reserve taking too long (#1391)

gdkchan 5 лет назад
Родитель
Сommit
46f8cef6a9

+ 23 - 17
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<KThread> _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<KThread>();
         }
@@ -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)
                 {

+ 22 - 25
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;