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
This commit is contained in:
riperiperi 2021-08-29 20:03:41 +01:00 committed by GitHub
parent 76e8f9ac87
commit 54adc5f9fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -35,6 +35,7 @@ namespace Ryujinx.Memory.Tracking
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 readonly List<VirtualRegion> _regions;
private readonly MemoryTracking _tracking;
@ -115,17 +116,16 @@ namespace Ryujinx.Memory.Tracking
/// <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)
{
RegionSignal action = Interlocked.Exchange(ref _preAction, null);
// If this handle was already unmapped (even if just partially),
// then we have nothing to do until it is mapped again.
// The pre-action should be still consumed to avoid flushing on remap.
if (Unmapped)
{
Interlocked.Exchange(ref _preAction, null);
return;
}
if (action != null)
if (_preAction != null)
{
// Copy the handles list in case it changes when we're out of the lock.
if (handleIterable is List<RegionHandle>)
@ -138,7 +138,12 @@ namespace Ryujinx.Memory.Tracking
try
{
action.Invoke(address, size);
lock (_preActionLock)
{
_preAction?.Invoke(address, size);
_preAction = null;
}
}
finally
{
@ -220,14 +225,19 @@ namespace Ryujinx.Memory.Tracking
{
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();
}
}
}
}