NativeReaderWriterLock.cs 2.5 KB

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