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

Ensure that all threads wait for a read tracking action to complete. (#2597)

* Lock around tracking action consume + execute. Not particularly fast.

* Lock around preaction registration and use

* Create a lock object

* Nit
riperiperi 4 лет назад
Родитель
Сommit
54adc5f9fb
1 измененных файлов с 19 добавлено и 9 удалено
  1. 19 9
      Ryujinx.Memory/Tracking/RegionHandle.cs

+ 19 - 9
Ryujinx.Memory/Tracking/RegionHandle.cs

@@ -35,6 +35,7 @@ namespace Ryujinx.Memory.Tracking
 
 
         private event Action _onDirty;
         private event Action _onDirty;
 
 
+        private object _preActionLock = new object();
         private RegionSignal _preAction; // Action to perform before a read or write. This will block the memory access.
         private RegionSignal _preAction; // Action to perform before a read or write. This will block the memory access.
         private readonly List<VirtualRegion> _regions;
         private readonly List<VirtualRegion> _regions;
         private readonly MemoryTracking _tracking;
         private readonly MemoryTracking _tracking;
@@ -115,17 +116,16 @@ namespace Ryujinx.Memory.Tracking
         /// <param name="write">Whether the region was written to or read</param>
         /// <param name="write">Whether the region was written to or read</param>
         internal void Signal(ulong address, ulong size, bool write, ref IList<RegionHandle> handleIterable)
         internal void Signal(ulong address, ulong size, bool write, ref IList<RegionHandle> handleIterable)
         {
         {
-            RegionSignal action = Interlocked.Exchange(ref _preAction, null);
-
             // If this handle was already unmapped (even if just partially),
             // If this handle was already unmapped (even if just partially),
             // then we have nothing to do until it is mapped again.
             // then we have nothing to do until it is mapped again.
             // The pre-action should be still consumed to avoid flushing on remap.
             // The pre-action should be still consumed to avoid flushing on remap.
             if (Unmapped)
             if (Unmapped)
             {
             {
+                Interlocked.Exchange(ref _preAction, null);
                 return;
                 return;
             }
             }
 
 
-            if (action != null)
+            if (_preAction != null)
             {
             {
                 // Copy the handles list in case it changes when we're out of the lock.
                 // Copy the handles list in case it changes when we're out of the lock.
                 if (handleIterable is List<RegionHandle>)
                 if (handleIterable is List<RegionHandle>)
@@ -138,7 +138,12 @@ namespace Ryujinx.Memory.Tracking
 
 
                 try
                 try
                 {
                 {
-                    action.Invoke(address, size);
+                    lock (_preActionLock)
+                    {
+                        _preAction?.Invoke(address, size);
+
+                        _preAction = null;
+                    }
                 }
                 }
                 finally
                 finally
                 {
                 {
@@ -220,14 +225,19 @@ namespace Ryujinx.Memory.Tracking
         {
         {
             ClearVolatile();
             ClearVolatile();
 
 
-            RegionSignal lastAction = Interlocked.Exchange(ref _preAction, action);
-            if (lastAction == null && action != lastAction)
+            lock (_preActionLock)
             {
             {
-                lock (_tracking.TrackingLock)
+                RegionSignal lastAction = _preAction;
+                _preAction = action;
+
+                if (lastAction == null && action != lastAction)
                 {
                 {
-                    foreach (VirtualRegion region in _regions)
+                    lock (_tracking.TrackingLock)
                     {
                     {
-                        region.UpdateProtection();
+                        foreach (VirtualRegion region in _regions)
+                        {
+                            region.UpdateProtection();
+                        }
                     }
                     }
                 }
                 }
             }
             }