Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions src/System.Private.CoreLib/src/System/Threading/SpinLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@

// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// SpinLock.cs
// A spin lock is a mutual exclusion lock primitive where a thread trying to acquire the lock waits in a loop ("spins")
// repeatedly checking until the lock becomes available. As the thread remains active performing a non-useful task,
// the use of such a lock is a kind of busy waiting and consumes CPU resources without performing real work.
//

//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

using Internal.Threading.Tracing;

Expand Down Expand Up @@ -104,7 +102,7 @@ public struct SpinLock
// The waiters count is calculated by m_owner & WAITERS_MASK 01111....110
private static int MAXIMUM_WAITERS = WAITERS_MASK;


[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int CompareExchange(ref int location, int value, int comparand, ref bool success)
{
int result = Interlocked.CompareExchange(ref location, value, comparand);
Expand All @@ -131,7 +129,6 @@ public SpinLock(bool enableThreadOwnerTracking)
}
}


/// <summary>
/// Initializes a new instance of the <see cref="T:System.Threading.SpinLock"/>
/// structure with the option to track thread IDs to improve debugging.
Expand Down Expand Up @@ -189,7 +186,22 @@ public void Enter(ref bool lockTaken)
/// </exception>
public void TryEnter(ref bool lockTaken)
{
TryEnter(0, ref lockTaken);
int observedOwner = m_owner;
if (((observedOwner & LOCK_ID_DISABLE_MASK) == 0) | lockTaken)
{
// Thread tracking enabled or invalid arg. Take slow path.
ContinueTryEnter(0, ref lockTaken);
}
else if ((observedOwner & LOCK_ANONYMOUS_OWNED) != 0)
{
// Lock already held by someone
lockTaken = false;
}
else
{
// Lock wasn't held; try to acquire it.
CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken);
}
}

/// <summary>
Expand Down Expand Up @@ -286,7 +298,6 @@ private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)
nameof(millisecondsTimeout), millisecondsTimeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
}


uint startTime = 0;
if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0)
{
Expand Down Expand Up @@ -323,10 +334,15 @@ private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)
observedOwner = m_owner;
if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
if (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner
|| millisecondsTimeout == 0)
if (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
{
// Aquired lock
return;
}

if (millisecondsTimeout == 0)
{
// Aquired lock, or did not aquire lock as owned but timeout is 0 so fail fast
// Did not aquire lock in CompareExchange and timeout is 0 so fail fast
return;
}
}
Expand Down Expand Up @@ -496,7 +512,6 @@ private void ContinueTryEnterWithThreadTracking(int millisecondsTimeout, uint st
/// <exception cref="SynchronizationLockException">
/// Thread ownership tracking is enabled, and the current thread is not the owner of this lock.
/// </exception>
//[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit()
{
//This is the fast path for the thread tracking is disabled, otherwise go to the slow path
Expand All @@ -522,15 +537,14 @@ public void Exit()
/// <exception cref="SynchronizationLockException">
/// Thread ownership tracking is enabled, and the current thread is not the owner of this lock.
/// </exception>
//[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit(bool useMemoryBarrier)
{
// This is the fast path for the thread tracking is diabled and not to use memory barrier, otherwise go to the slow path
// The reason not to add else statement if the usememorybarrier is that it will add more barnching in the code and will prevent
// method inlining, so this is optimized for useMemoryBarrier=false and Exit() overload optimized for useMemoryBarrier=true
if ((m_owner & LOCK_ID_DISABLE_MASK) != 0 && !useMemoryBarrier)
// method inlining, so this is optimized for useMemoryBarrier=false and Exit() overload optimized for useMemoryBarrier=true.
int tmpOwner = m_owner;
if ((tmpOwner & LOCK_ID_DISABLE_MASK) != 0 & !useMemoryBarrier)
{
int tmpOwner = m_owner;
m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED);
}
else
Expand Down Expand Up @@ -577,7 +591,6 @@ private void ExitSlowPath(bool useMemoryBarrier)
/// </summary>
public bool IsHeld
{
//[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get
{
if (IsThreadOwnerTrackingEnabled)
Expand All @@ -603,7 +616,6 @@ public bool IsHeld
/// </exception>
public bool IsHeldByCurrentThread
{
//[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get
{
if (!IsThreadOwnerTrackingEnabled)
Expand All @@ -617,7 +629,6 @@ public bool IsHeldByCurrentThread
/// <summary>Gets whether thread ownership tracking is enabled for this instance.</summary>
public bool IsThreadOwnerTrackingEnabled
{
//[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get { return (m_owner & LOCK_ID_DISABLE_MASK) == 0; }
}

Expand Down