diff --git a/src/libraries/System.Threading/tests/System.Threading.Tests.csproj b/src/libraries/System.Threading/tests/System.Threading.Tests.csproj index 72dce9430be633..cb21b19ae3a8c9 100644 --- a/src/libraries/System.Threading/tests/System.Threading.Tests.csproj +++ b/src/libraries/System.Threading/tests/System.Threading.Tests.csproj @@ -34,6 +34,7 @@ + diff --git a/src/libraries/System.Threading/tests/VolatileTests.cs b/src/libraries/System.Threading/tests/VolatileTests.cs new file mode 100644 index 00000000000000..2646e3edfeb931 --- /dev/null +++ b/src/libraries/System.Threading/tests/VolatileTests.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using Xunit; + +namespace System.Threading.Tests +{ + public class VolatileTests + { + [Fact] + public void Barriers_DoNotThrow() + { + Volatile.ReadBarrier(); + Volatile.WriteBarrier(); + } + + [Fact] + public void BarriersViaReflection() + { + MethodInfo readBarrierMethod = typeof(Volatile).GetMethod(nameof(Volatile.ReadBarrier), BindingFlags.Public | BindingFlags.Static); + MethodInfo writeBarrierMethod = typeof(Volatile).GetMethod(nameof(Volatile.WriteBarrier), BindingFlags.Public | BindingFlags.Static); + Assert.NotNull(readBarrierMethod); + Assert.NotNull(writeBarrierMethod); + readBarrierMethod.Invoke(null, null); + writeBarrierMethod.Invoke(null, null); + } + + [Fact] + public void BarriersAndVolatileOperations() + { + int value1 = 0; + int value2 = 0; + long value3 = 0; + + Volatile.ReadBarrier(); + Volatile.WriteBarrier(); + + Volatile.Write(ref value1, 42); + Volatile.WriteBarrier(); + Assert.Equal(42, value1); + + Volatile.ReadBarrier(); + int result1 = Volatile.Read(ref value1); + Assert.Equal(42, result1); + + Volatile.ReadBarrier(); + Volatile.ReadBarrier(); + Volatile.WriteBarrier(); + Volatile.WriteBarrier(); + + Volatile.Write(ref value2, 100); + Volatile.WriteBarrier(); + Volatile.ReadBarrier(); + int result2 = Volatile.Read(ref value2); + Assert.Equal(100, result2); + + Volatile.Write(ref value3, 123456789L); + Volatile.ReadBarrier(); + long result3 = Volatile.Read(ref value3); + Assert.Equal(123456789L, result3); + } + } +} diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 57c9893a0c274f..e27b3e2daa26a9 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2588,6 +2588,9 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } else if (in_corlib && !strcmp (klass_name_space, "System.Threading") && !strcmp (klass_name, "Thread")) { if (!strcmp (tm, "MemoryBarrier") && csignature->param_count == 0) *op = MINT_MONO_MEMORY_BARRIER; + } else if (in_corlib && !strcmp (klass_name_space, "System.Threading") && !strcmp (klass_name, "Volatile")) { + if ((!strcmp (tm, "ReadBarrier") || !strcmp (tm, "WriteBarrier")) && csignature->param_count == 0) + *op = MINT_MONO_MEMORY_BARRIER; } else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.CompilerServices") && !strcmp (klass_name, "JitHelpers") &&