Browse Source

Fix ThreadingLock deadlock on invalid access and TerminateProcess (#3407)

gdkchan 3 years ago
parent
commit
232b1012b0
2 changed files with 33 additions and 20 deletions
  1. 3 1
      Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
  2. 30 19
      Ryujinx.Memory/Tracking/MemoryTracking.cs

+ 3 - 1
Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs

@@ -966,6 +966,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
                 SignalExitToDebugExited();
                 SignalExit();
             }
+
+            KernelStatic.GetCurrentThread().Exit();
         }
 
         private void UnpauseAndTerminateAllThreadsExcept(KThread currentThread)
@@ -981,7 +983,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
 
                 foreach (KThread thread in _threads)
                 {
-                    if ((thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending)
+                    if (thread != currentThread && (thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending)
                     {
                         thread.PrepareForTermination();
                     }

+ 30 - 19
Ryujinx.Memory/Tracking/MemoryTracking.cs

@@ -227,6 +227,8 @@ namespace Ryujinx.Memory.Tracking
             // Look up the virtual region using the region list.
             // Signal up the chain to relevant handles.
 
+            bool shouldThrow = false;
+
             lock (TrackingLock)
             {
                 ref var overlaps = ref ThreadStaticArray<VirtualRegion>.Get();
@@ -235,34 +237,43 @@ namespace Ryujinx.Memory.Tracking
 
                 if (count == 0 && !precise)
                 {
-                    if (!_memoryManager.IsMapped(address))
+                    if (_memoryManager.IsMapped(address))
                     {
-                        _invalidAccessHandler?.Invoke(address);
-
-                        // We can't continue - it's impossible to remove protection from the page.
-                        // Even if the access handler wants us to continue, we wouldn't be able to.
-                        throw new InvalidMemoryRegionException();
+                        _memoryManager.TrackingReprotect(address & ~(ulong)(_pageSize - 1), (ulong)_pageSize, MemoryPermission.ReadAndWrite);
+                        return false; // We can't handle this - it's probably a real invalid access.
                     }
-
-                    _memoryManager.TrackingReprotect(address & ~(ulong)(_pageSize - 1), (ulong)_pageSize, MemoryPermission.ReadAndWrite);
-                    return false; // We can't handle this - it's probably a real invalid access.
-                }
-
-                for (int i = 0; i < count; i++)
-                {
-                    VirtualRegion region = overlaps[i];
-
-                    if (precise)
+                    else
                     {
-                        region.SignalPrecise(address, size, write);
+                        shouldThrow = true;
                     }
-                    else
+                }
+                else
+                {
+                    for (int i = 0; i < count; i++)
                     {
-                        region.Signal(address, size, write);
+                        VirtualRegion region = overlaps[i];
+
+                        if (precise)
+                        {
+                            region.SignalPrecise(address, size, write);
+                        }
+                        else
+                        {
+                            region.Signal(address, size, write);
+                        }
                     }
                 }
             }
 
+            if (shouldThrow)
+            {
+                _invalidAccessHandler?.Invoke(address);
+
+                // We can't continue - it's impossible to remove protection from the page.
+                // Even if the access handler wants us to continue, we wouldn't be able to.
+                throw new InvalidMemoryRegionException();
+            }
+
             return true;
         }