Assert.Equal(0x17755771u, value);
}
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArm64Process))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/11177")]
+ [Fact]
public void MemoryBarrierProcessWide()
{
// Stress MemoryBarrierProcessWide correctness using a simple AsymmetricLock
// Returning LockCookie to call Exit on is the fastest implementation because of it works naturally with the RCU pattern.
// The traditional Enter/Exit lock interface would require thread local storage or some other scheme to reclaim the cookie.
- // Returning LockCookie to call Exit on is the fastest implementation because of it works naturally with the RCU pattern.
- // The traditional Enter/Exit lock interface would require thread local storage or some other scheme to reclaim the cookie.
public LockCookie Enter()
{
int currentThreadId = Environment.CurrentManagedThreadId;
//
if (VolatileReadWithoutBarrier(ref _current) == entry)
{
+ // at this point we know for sure that we own the lock.
return entry;
}
var oldEntry = _current;
_current = new LockCookie(Environment.CurrentManagedThreadId);
- // After MemoryBarrierProcessWide, we can be sure that the Volatile.Read done by the fast thread will see that it is not a fast
- // thread anymore, and thus it will not attempt to enter the lock.
+ // MemoryBarrierProcessWide ensures, process-wide, that our write to _current becomes visible
+ // to every thread, and all writes by other threads become visible to us before we can continue.
+ // As a result any other thread that sets Taken to true either:
+ // a) made it past the read of _current and owns the lock OR
+ // b) will see that _current has changed and will revert Taken without taking the lock
+ // Thus we only need to wait for 'Taken' to become false and claim the lock for ourselves.
+ // 'Taken' may yet switch to true after that, but that cannot result in other thread owning the lock.
Interlocked.MemoryBarrierProcessWide();
// Keep looping as long as the lock is taken by other thread