Replace ReaderWriterLock with ReaderWriterLockSlim (#5785)

* Replace ReaderWriterLock with ReaderWriterLockSlim

* Resolve Feedback + Correct typo

* Revert some unncessary logic
This commit is contained in:
sunshineinabox 2023-10-12 09:11:15 -07:00 committed by GitHub
parent 4e2bb13080
commit e768a54f17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 56 deletions

View file

@ -7,14 +7,14 @@ namespace ARMeilleure.Translation
internal class TranslatorCache<T> internal class TranslatorCache<T>
{ {
private readonly IntervalTree<ulong, T> _tree; private readonly IntervalTree<ulong, T> _tree;
private readonly ReaderWriterLock _treeLock; private readonly ReaderWriterLockSlim _treeLock;
public int Count => _tree.Count; public int Count => _tree.Count;
public TranslatorCache() public TranslatorCache()
{ {
_tree = new IntervalTree<ulong, T>(); _tree = new IntervalTree<ulong, T>();
_treeLock = new ReaderWriterLock(); _treeLock = new ReaderWriterLockSlim();
} }
public bool TryAdd(ulong address, ulong size, T value) public bool TryAdd(ulong address, ulong size, T value)
@ -24,70 +24,70 @@ namespace ARMeilleure.Translation
public bool AddOrUpdate(ulong address, ulong size, T value, Func<ulong, T, T> updateFactoryCallback) public bool AddOrUpdate(ulong address, ulong size, T value, Func<ulong, T, T> updateFactoryCallback)
{ {
_treeLock.AcquireWriterLock(Timeout.Infinite); _treeLock.EnterWriteLock();
bool result = _tree.AddOrUpdate(address, address + size, value, updateFactoryCallback); bool result = _tree.AddOrUpdate(address, address + size, value, updateFactoryCallback);
_treeLock.ReleaseWriterLock(); _treeLock.ExitWriteLock();
return result; return result;
} }
public T GetOrAdd(ulong address, ulong size, T value) public T GetOrAdd(ulong address, ulong size, T value)
{ {
_treeLock.AcquireWriterLock(Timeout.Infinite); _treeLock.EnterWriteLock();
value = _tree.GetOrAdd(address, address + size, value); value = _tree.GetOrAdd(address, address + size, value);
_treeLock.ReleaseWriterLock(); _treeLock.ExitWriteLock();
return value; return value;
} }
public bool Remove(ulong address) public bool Remove(ulong address)
{ {
_treeLock.AcquireWriterLock(Timeout.Infinite); _treeLock.EnterWriteLock();
bool removed = _tree.Remove(address) != 0; bool removed = _tree.Remove(address) != 0;
_treeLock.ReleaseWriterLock(); _treeLock.ExitWriteLock();
return removed; return removed;
} }
public void Clear() public void Clear()
{ {
_treeLock.AcquireWriterLock(Timeout.Infinite); _treeLock.EnterWriteLock();
_tree.Clear(); _tree.Clear();
_treeLock.ReleaseWriterLock(); _treeLock.ExitWriteLock();
} }
public bool ContainsKey(ulong address) public bool ContainsKey(ulong address)
{ {
_treeLock.AcquireReaderLock(Timeout.Infinite); _treeLock.EnterReadLock();
bool result = _tree.ContainsKey(address); bool result = _tree.ContainsKey(address);
_treeLock.ReleaseReaderLock(); _treeLock.ExitReadLock();
return result; return result;
} }
public bool TryGetValue(ulong address, out T value) public bool TryGetValue(ulong address, out T value)
{ {
_treeLock.AcquireReaderLock(Timeout.Infinite); _treeLock.EnterReadLock();
bool result = _tree.TryGet(address, out value); bool result = _tree.TryGet(address, out value);
_treeLock.ReleaseReaderLock(); _treeLock.ExitReadLock();
return result; return result;
} }
public int GetOverlaps(ulong address, ulong size, ref ulong[] overlaps) public int GetOverlaps(ulong address, ulong size, ref ulong[] overlaps)
{ {
_treeLock.AcquireReaderLock(Timeout.Infinite); _treeLock.EnterReadLock();
int count = _tree.Get(address, address + size, ref overlaps); int count = _tree.Get(address, address + size, ref overlaps);
_treeLock.ReleaseReaderLock(); _treeLock.ExitReadLock();
return count; return count;
} }
public List<T> AsList() public List<T> AsList()
{ {
_treeLock.AcquireReaderLock(Timeout.Infinite); _treeLock.EnterReadLock();
List<T> list = _tree.AsList(); List<T> list = _tree.AsList();
_treeLock.ReleaseReaderLock(); _treeLock.ExitReadLock();
return list; return list;
} }

View file

@ -5,7 +5,7 @@ namespace Ryujinx.Common
{ {
public class ReactiveObject<T> public class ReactiveObject<T>
{ {
private readonly ReaderWriterLock _readerWriterLock = new(); private readonly ReaderWriterLockSlim _readerWriterLock = new();
private bool _isInitialized; private bool _isInitialized;
private T _value; private T _value;
@ -15,15 +15,15 @@ namespace Ryujinx.Common
{ {
get get
{ {
_readerWriterLock.AcquireReaderLock(Timeout.Infinite); _readerWriterLock.EnterReadLock();
T value = _value; T value = _value;
_readerWriterLock.ReleaseReaderLock(); _readerWriterLock.ExitReadLock();
return value; return value;
} }
set set
{ {
_readerWriterLock.AcquireWriterLock(Timeout.Infinite); _readerWriterLock.EnterWriteLock();
T oldValue = _value; T oldValue = _value;
@ -32,7 +32,7 @@ namespace Ryujinx.Common
_isInitialized = true; _isInitialized = true;
_value = value; _value = value;
_readerWriterLock.ReleaseWriterLock(); _readerWriterLock.ExitWriteLock();
if (!oldIsInitialized || oldValue == null || !oldValue.Equals(_value)) if (!oldIsInitialized || oldValue == null || !oldValue.Equals(_value))
{ {

View file

@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Vulkan
private int _flushTemp; private int _flushTemp;
private int _lastFlushWrite = -1; private int _lastFlushWrite = -1;
private readonly ReaderWriterLock _flushLock; private readonly ReaderWriterLockSlim _flushLock;
private FenceHolder _flushFence; private FenceHolder _flushFence;
private int _flushWaiting; private int _flushWaiting;
@ -85,7 +85,7 @@ namespace Ryujinx.Graphics.Vulkan
_currentType = currentType; _currentType = currentType;
DesiredType = currentType; DesiredType = currentType;
_flushLock = new ReaderWriterLock(); _flushLock = new ReaderWriterLockSlim();
_useMirrors = gd.IsTBDR; _useMirrors = gd.IsTBDR;
} }
@ -106,7 +106,7 @@ namespace Ryujinx.Graphics.Vulkan
_currentType = currentType; _currentType = currentType;
DesiredType = currentType; DesiredType = currentType;
_flushLock = new ReaderWriterLock(); _flushLock = new ReaderWriterLockSlim();
} }
public bool TryBackingSwap(ref CommandBufferScoped? cbs) public bool TryBackingSwap(ref CommandBufferScoped? cbs)
@ -116,7 +116,7 @@ namespace Ryujinx.Graphics.Vulkan
// Only swap if the buffer is not used in any queued command buffer. // Only swap if the buffer is not used in any queued command buffer.
bool isRented = _buffer.HasRentedCommandBufferDependency(_gd.CommandBufferPool); bool isRented = _buffer.HasRentedCommandBufferDependency(_gd.CommandBufferPool);
if (!isRented && _gd.CommandBufferPool.OwnedByCurrentThread && !_flushLock.IsReaderLockHeld && (_pendingData == null || cbs != null)) if (!isRented && _gd.CommandBufferPool.OwnedByCurrentThread && !_flushLock.IsReadLockHeld && (_pendingData == null || cbs != null))
{ {
var currentAllocation = _allocationAuto; var currentAllocation = _allocationAuto;
var currentBuffer = _buffer; var currentBuffer = _buffer;
@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Vulkan
ClearMirrors(cbs.Value, 0, Size); ClearMirrors(cbs.Value, 0, Size);
} }
_flushLock.AcquireWriterLock(Timeout.Infinite); _flushLock.EnterWriteLock();
ClearFlushFence(); ClearFlushFence();
@ -185,7 +185,7 @@ namespace Ryujinx.Graphics.Vulkan
_gd.PipelineInternal.SwapBuffer(currentBuffer, _buffer); _gd.PipelineInternal.SwapBuffer(currentBuffer, _buffer);
_flushLock.ReleaseWriterLock(); _flushLock.ExitWriteLock();
} }
_swapQueued = false; _swapQueued = false;
@ -548,42 +548,44 @@ namespace Ryujinx.Graphics.Vulkan
private void WaitForFlushFence() private void WaitForFlushFence()
{ {
// Assumes the _flushLock is held as reader, returns in same state. if (_flushFence == null)
{
return;
}
// If storage has changed, make sure the fence has been reached so that the data is in place.
_flushLock.ExitReadLock();
_flushLock.EnterWriteLock();
if (_flushFence != null) if (_flushFence != null)
{ {
// If storage has changed, make sure the fence has been reached so that the data is in place. var fence = _flushFence;
Interlocked.Increment(ref _flushWaiting);
var cookie = _flushLock.UpgradeToWriterLock(Timeout.Infinite); // Don't wait in the lock.
if (_flushFence != null) _flushLock.ExitWriteLock();
fence.Wait();
_flushLock.EnterWriteLock();
if (Interlocked.Decrement(ref _flushWaiting) == 0)
{ {
var fence = _flushFence; fence.Put();
Interlocked.Increment(ref _flushWaiting);
// Don't wait in the lock.
var restoreCookie = _flushLock.ReleaseLock();
fence.Wait();
_flushLock.RestoreLock(ref restoreCookie);
if (Interlocked.Decrement(ref _flushWaiting) == 0)
{
fence.Put();
}
_flushFence = null;
} }
_flushLock.DowngradeFromWriterLock(ref cookie); _flushFence = null;
} }
// Assumes the _flushLock is held as reader, returns in same state.
_flushLock.ExitWriteLock();
_flushLock.EnterReadLock();
} }
public PinnedSpan<byte> GetData(int offset, int size) public PinnedSpan<byte> GetData(int offset, int size)
{ {
_flushLock.AcquireReaderLock(Timeout.Infinite); _flushLock.EnterReadLock();
WaitForFlushFence(); WaitForFlushFence();
@ -603,7 +605,7 @@ namespace Ryujinx.Graphics.Vulkan
// Need to be careful here, the buffer can't be unmapped while the data is being used. // Need to be careful here, the buffer can't be unmapped while the data is being used.
_buffer.IncrementReferenceCount(); _buffer.IncrementReferenceCount();
_flushLock.ReleaseReaderLock(); _flushLock.ExitReadLock();
return PinnedSpan<byte>.UnsafeFromSpan(result, _buffer.DecrementReferenceCount); return PinnedSpan<byte>.UnsafeFromSpan(result, _buffer.DecrementReferenceCount);
} }
@ -621,7 +623,7 @@ namespace Ryujinx.Graphics.Vulkan
result = resource.GetFlushBuffer().GetBufferData(resource.GetPool(), this, offset, size); result = resource.GetFlushBuffer().GetBufferData(resource.GetPool(), this, offset, size);
} }
_flushLock.ReleaseReaderLock(); _flushLock.ExitReadLock();
// Flush buffer is pinned until the next GetBufferData on the thread, which is fine for current uses. // Flush buffer is pinned until the next GetBufferData on the thread, which is fine for current uses.
return PinnedSpan<byte>.UnsafeFromSpan(result); return PinnedSpan<byte>.UnsafeFromSpan(result);
@ -1073,11 +1075,11 @@ namespace Ryujinx.Graphics.Vulkan
_allocationAuto.Dispose(); _allocationAuto.Dispose();
} }
_flushLock.AcquireWriterLock(Timeout.Infinite); _flushLock.EnterWriteLock();
ClearFlushFence(); ClearFlushFence();
_flushLock.ReleaseWriterLock(); _flushLock.ExitWriteLock();
} }
} }
} }