Volatile.cs 7.7 KB

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