ConcurrentBitmap.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. using System;
  2. using System.Threading;
  3. namespace Ryujinx.Memory.Tracking
  4. {
  5. /// <summary>
  6. /// A bitmap that can be safely modified from multiple threads.
  7. /// </summary>
  8. internal class ConcurrentBitmap
  9. {
  10. public const int IntSize = 64;
  11. public const int IntShift = 6;
  12. public const int IntMask = IntSize - 1;
  13. /// <summary>
  14. /// Masks representing the bitmap. Least significant bit first, 64-bits per mask.
  15. /// </summary>
  16. public readonly long[] Masks;
  17. /// <summary>
  18. /// Create a new multithreaded bitmap.
  19. /// </summary>
  20. /// <param name="count">The number of bits to reserve</param>
  21. /// <param name="set">Whether the bits should be initially set or not</param>
  22. public ConcurrentBitmap(int count, bool set)
  23. {
  24. Masks = new long[(count + IntMask) / IntSize];
  25. if (set)
  26. {
  27. Array.Fill(Masks, -1L);
  28. }
  29. }
  30. /// <summary>
  31. /// Check if any bit in the bitmap is set.
  32. /// </summary>
  33. /// <returns>True if any bits are set, false otherwise</returns>
  34. public bool AnySet()
  35. {
  36. for (int i = 0; i < Masks.Length; i++)
  37. {
  38. if (Volatile.Read(ref Masks[i]) != 0)
  39. {
  40. return true;
  41. }
  42. }
  43. return false;
  44. }
  45. /// <summary>
  46. /// Check if a bit in the bitmap is set.
  47. /// </summary>
  48. /// <param name="bit">The bit index to check</param>
  49. /// <returns>True if the bit is set, false otherwise</returns>
  50. public bool IsSet(int bit)
  51. {
  52. int wordIndex = bit >> IntShift;
  53. int wordBit = bit & IntMask;
  54. long wordMask = 1L << wordBit;
  55. return (Volatile.Read(ref Masks[wordIndex]) & wordMask) != 0;
  56. }
  57. /// <summary>
  58. /// Check if any bit in a range of bits in the bitmap are set. (inclusive)
  59. /// </summary>
  60. /// <param name="start">The first bit index to check</param>
  61. /// <param name="end">The last bit index to check</param>
  62. /// <returns>True if a bit is set, false otherwise</returns>
  63. public bool IsSet(int start, int end)
  64. {
  65. if (start == end)
  66. {
  67. return IsSet(start);
  68. }
  69. int startIndex = start >> IntShift;
  70. int startBit = start & IntMask;
  71. long startMask = -1L << startBit;
  72. int endIndex = end >> IntShift;
  73. int endBit = end & IntMask;
  74. long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
  75. long startValue = Volatile.Read(ref Masks[startIndex]);
  76. if (startIndex == endIndex)
  77. {
  78. return (startValue & startMask & endMask) != 0;
  79. }
  80. if ((startValue & startMask) != 0)
  81. {
  82. return true;
  83. }
  84. for (int i = startIndex + 1; i < endIndex; i++)
  85. {
  86. if (Volatile.Read(ref Masks[i]) != 0)
  87. {
  88. return true;
  89. }
  90. }
  91. long endValue = Volatile.Read(ref Masks[endIndex]);
  92. if ((endValue & endMask) != 0)
  93. {
  94. return true;
  95. }
  96. return false;
  97. }
  98. /// <summary>
  99. /// Set a bit at a specific index to either true or false.
  100. /// </summary>
  101. /// <param name="bit">The bit index to set</param>
  102. /// <param name="value">Whether the bit should be set or not</param>
  103. public void Set(int bit, bool value)
  104. {
  105. int wordIndex = bit >> IntShift;
  106. int wordBit = bit & IntMask;
  107. long wordMask = 1L << wordBit;
  108. long existing;
  109. long newValue;
  110. do
  111. {
  112. existing = Volatile.Read(ref Masks[wordIndex]);
  113. if (value)
  114. {
  115. newValue = existing | wordMask;
  116. }
  117. else
  118. {
  119. newValue = existing & ~wordMask;
  120. }
  121. }
  122. while (Interlocked.CompareExchange(ref Masks[wordIndex], newValue, existing) != existing);
  123. }
  124. /// <summary>
  125. /// Clear the bitmap entirely, setting all bits to 0.
  126. /// </summary>
  127. public void Clear()
  128. {
  129. for (int i = 0; i < Masks.Length; i++)
  130. {
  131. Volatile.Write(ref Masks[i], 0);
  132. }
  133. }
  134. }
  135. }