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:
parent
76e8f9ac87
commit
54adc5f9fb
1 changed files with 19 additions and 9 deletions
|
@ -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);
|
lock (_preActionLock)
|
||||||
if (lastAction == null && action != lastAction)
|
|
||||||
{
|
{
|
||||||
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue