Volatile.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Runtime.CompilerServices;
  5. using System.Runtime.Versioning;
  6. using Internal.Runtime.CompilerServices;
  7. namespace System.Threading
  8. {
  9. /// <summary>Methods for accessing memory with volatile semantics.</summary>
  10. public static unsafe class Volatile
  11. {
  12. // The VM may replace these implementations with more efficient ones in some cases.
  13. // In coreclr, for example, see getILIntrinsicImplementationForVolatile() in jitinterface.cpp.
  14. #region Boolean
  15. private struct VolatileBoolean { public volatile bool Value; }
  16. [Intrinsic]
  17. [NonVersionable]
  18. public static bool Read(ref bool location) =>
  19. Unsafe.As<bool, VolatileBoolean>(ref location).Value;
  20. [Intrinsic]
  21. [NonVersionable]
  22. public static void Write(ref bool location, bool value) =>
  23. Unsafe.As<bool, VolatileBoolean>(ref location).Value = value;
  24. #endregion
  25. #region Byte
  26. private struct VolatileByte { public volatile byte Value; }
  27. [Intrinsic]
  28. [NonVersionable]
  29. public static byte Read(ref byte location) =>
  30. Unsafe.As<byte, VolatileByte>(ref location).Value;
  31. [Intrinsic]
  32. [NonVersionable]
  33. public static void Write(ref byte location, byte value) =>
  34. Unsafe.As<byte, VolatileByte>(ref location).Value = value;
  35. #endregion
  36. #region Double
  37. [Intrinsic]
  38. [NonVersionable]
  39. public static double Read(ref double location)
  40. {
  41. long result = Read(ref Unsafe.As<double, long>(ref location));
  42. return *(double*)&result;
  43. }
  44. [Intrinsic]
  45. [NonVersionable]
  46. public static void Write(ref double location, double value) =>
  47. Write(ref Unsafe.As<double, long>(ref location), *(long*)&value);
  48. #endregion
  49. #region Int16
  50. private struct VolatileInt16 { public volatile short Value; }
  51. [Intrinsic]
  52. [NonVersionable]
  53. public static short Read(ref short location) =>
  54. Unsafe.As<short, VolatileInt16>(ref location).Value;
  55. [Intrinsic]
  56. [NonVersionable]
  57. public static void Write(ref short location, short value) =>
  58. Unsafe.As<short, VolatileInt16>(ref location).Value = value;
  59. #endregion
  60. #region Int32
  61. private struct VolatileInt32 { public volatile int Value; }
  62. [Intrinsic]
  63. [NonVersionable]
  64. public static int Read(ref int location) =>
  65. Unsafe.As<int, VolatileInt32>(ref location).Value;
  66. [Intrinsic]
  67. [NonVersionable]
  68. public static void Write(ref int location, int value) =>
  69. Unsafe.As<int, VolatileInt32>(ref location).Value = value;
  70. #endregion
  71. #region Int64
  72. [Intrinsic]
  73. [NonVersionable]
  74. public static long Read(ref long location) =>
  75. #if BIT64
  76. (Int64)Unsafe.As<Int64, VolatileIntPtr>(ref location).Value;
  77. #else
  78. // On 32-bit machines, we use Interlocked, since an ordinary volatile read would not be atomic.
  79. Interlocked.CompareExchange(ref location, 0, 0);
  80. #endif
  81. [Intrinsic]
  82. [NonVersionable]
  83. public static void Write(ref long location, long value) =>
  84. #if BIT64
  85. Unsafe.As<Int64, VolatileIntPtr>(ref location).Value = (IntPtr)value;
  86. #else
  87. // On 32-bit, we use Interlocked, since an ordinary volatile write would not be atomic.
  88. Interlocked.Exchange(ref location, value);
  89. #endif
  90. #endregion
  91. #region IntPtr
  92. private struct VolatileIntPtr { public volatile IntPtr Value; }
  93. [Intrinsic]
  94. [NonVersionable]
  95. public static IntPtr Read(ref IntPtr location) =>
  96. Unsafe.As<IntPtr, VolatileIntPtr>(ref location).Value;
  97. [Intrinsic]
  98. [NonVersionable]
  99. public static void Write(ref IntPtr location, IntPtr value) =>
  100. Unsafe.As<IntPtr, VolatileIntPtr>(ref location).Value = value;
  101. #endregion
  102. #region SByte
  103. private struct VolatileSByte { public volatile sbyte Value; }
  104. [CLSCompliant(false)]
  105. [Intrinsic]
  106. [NonVersionable]
  107. public static sbyte Read(ref sbyte location) =>
  108. Unsafe.As<sbyte, VolatileSByte>(ref location).Value;
  109. [CLSCompliant(false)]
  110. [Intrinsic]
  111. [NonVersionable]
  112. public static void Write(ref sbyte location, sbyte value) =>
  113. Unsafe.As<sbyte, VolatileSByte>(ref location).Value = value;
  114. #endregion
  115. #region Single
  116. private struct VolatileSingle { public volatile float Value; }
  117. [Intrinsic]
  118. [NonVersionable]
  119. public static float Read(ref float location) =>
  120. Unsafe.As<float, VolatileSingle>(ref location).Value;
  121. [Intrinsic]
  122. [NonVersionable]
  123. public static void Write(ref float location, float value) =>
  124. Unsafe.As<float, VolatileSingle>(ref location).Value = value;
  125. #endregion
  126. #region UInt16
  127. private struct VolatileUInt16 { public volatile ushort Value; }
  128. [CLSCompliant(false)]
  129. [Intrinsic]
  130. [NonVersionable]
  131. public static ushort Read(ref ushort location) =>
  132. Unsafe.As<ushort, VolatileUInt16>(ref location).Value;
  133. [CLSCompliant(false)]
  134. [Intrinsic]
  135. [NonVersionable]
  136. public static void Write(ref ushort location, ushort value) =>
  137. Unsafe.As<ushort, VolatileUInt16>(ref location).Value = value;
  138. #endregion
  139. #region UInt32
  140. private struct VolatileUInt32 { public volatile uint Value; }
  141. [CLSCompliant(false)]
  142. [Intrinsic]
  143. [NonVersionable]
  144. public static uint Read(ref uint location) =>
  145. Unsafe.As<uint, VolatileUInt32>(ref location).Value;
  146. [CLSCompliant(false)]
  147. [Intrinsic]
  148. [NonVersionable]
  149. public static void Write(ref uint location, uint value) =>
  150. Unsafe.As<uint, VolatileUInt32>(ref location).Value = value;
  151. #endregion
  152. #region UInt64
  153. [CLSCompliant(false)]
  154. [Intrinsic]
  155. [NonVersionable]
  156. public static ulong Read(ref ulong location) =>
  157. (ulong)Read(ref Unsafe.As<ulong, long>(ref location));
  158. [CLSCompliant(false)]
  159. [Intrinsic]
  160. [NonVersionable]
  161. public static void Write(ref ulong location, ulong value) =>
  162. Write(ref Unsafe.As<ulong, long>(ref location), (long)value);
  163. #endregion
  164. #region UIntPtr
  165. private struct VolatileUIntPtr { public volatile UIntPtr Value; }
  166. [CLSCompliant(false)]
  167. [Intrinsic]
  168. [NonVersionable]
  169. public static UIntPtr Read(ref UIntPtr location) =>
  170. Unsafe.As<UIntPtr, VolatileUIntPtr>(ref location).Value;
  171. [CLSCompliant(false)]
  172. [Intrinsic]
  173. [NonVersionable]
  174. public static void Write(ref UIntPtr location, UIntPtr value) =>
  175. Unsafe.As<UIntPtr, VolatileUIntPtr>(ref location).Value = value;
  176. #endregion
  177. #region T
  178. private struct VolatileObject { public volatile object Value; }
  179. [Intrinsic]
  180. [NonVersionable]
  181. public static T Read<T>(ref T location) where T : class =>
  182. Unsafe.As<T>(Unsafe.As<T, VolatileObject>(ref location).Value);
  183. [Intrinsic]
  184. [NonVersionable]
  185. public static void Write<T>(ref T location, T value) where T : class =>
  186. Unsafe.As<T, VolatileObject>(ref location).Value = value;
  187. #endregion
  188. }
  189. }