NativeReaderWriterLock.cs
1 using System.Runtime.InteropServices; 2 using System.Threading; 3 using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers; 4 5 namespace Ryujinx.Common.Memory.PartialUnmaps 6 { 7 /// <summary> 8 /// A simple implementation of a ReaderWriterLock which can be used from native code. 9 /// </summary> 10 [StructLayout(LayoutKind.Sequential, Pack = 4)] 11 public struct NativeReaderWriterLock 12 { 13 public int WriteLock; 14 public int ReaderCount; 15 16 public static readonly int WriteLockOffset; 17 public static readonly int ReaderCountOffset; 18 19 /// <summary> 20 /// Populates the field offsets for use when emitting native code. 21 /// </summary> 22 static NativeReaderWriterLock() 23 { 24 NativeReaderWriterLock instance = new(); 25 26 WriteLockOffset = OffsetOf(ref instance, ref instance.WriteLock); 27 ReaderCountOffset = OffsetOf(ref instance, ref instance.ReaderCount); 28 } 29 30 /// <summary> 31 /// Acquires the reader lock. 32 /// </summary> 33 public void AcquireReaderLock() 34 { 35 // Must take write lock for a very short time to become a reader. 36 37 while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0) 38 { 39 } 40 41 Interlocked.Increment(ref ReaderCount); 42 43 Interlocked.Exchange(ref WriteLock, 0); 44 } 45 46 /// <summary> 47 /// Releases the reader lock. 48 /// </summary> 49 public void ReleaseReaderLock() 50 { 51 Interlocked.Decrement(ref ReaderCount); 52 } 53 54 /// <summary> 55 /// Upgrades to a writer lock. The reader lock is temporarily released while obtaining the writer lock. 56 /// </summary> 57 public void UpgradeToWriterLock() 58 { 59 // Prevent any more threads from entering reader. 60 // If the write lock is already taken, wait for it to not be taken. 61 62 Interlocked.Decrement(ref ReaderCount); 63 64 while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0) 65 { 66 } 67 68 // Wait for reader count to drop to 0, then take the lock again as the only reader. 69 70 while (Interlocked.CompareExchange(ref ReaderCount, 1, 0) != 0) 71 { 72 } 73 } 74 75 /// <summary> 76 /// Downgrades from a writer lock, back to a reader one. 77 /// </summary> 78 public void DowngradeFromWriterLock() 79 { 80 // Release the WriteLock. 81 82 Interlocked.Exchange(ref WriteLock, 0); 83 } 84 } 85 }