/// <summary>
/// Initializes a new instance of the <see cref="T:System.Threading.SpinLock"/>
/// structure with the option to track thread IDs to improve debugging.
/// </summary>
/// <remarks>
/// The default constructor for <see cref="SpinLock"/> tracks thread ownership.
/// </remarks>
/// <summary>
/// Acquires the lock in a reliable manner, such that even if an exception occurs within the method
/// call, <paramref name="lockTaken"/> can be examined reliably to determine whether the lock was
/// acquired.
/// </summary>
/// <remarks>
/// <see cref="SpinLock"/> is a non-reentrant lock, meaning that if a thread holds the lock, it is
/// not allowed to enter the lock again. If thread ownership tracking is enabled (whether it's
/// enabled is available through <see cref="IsThreadOwnerTrackingEnabled"/>), an exception will be
/// thrown when a thread tries to re-enter a lock it already holds. However, if thread ownership
/// tracking is disabled, attempting to enter a lock already held will result in deadlock.
/// </remarks>
/// <param name="lockTaken">True if the lock is acquired; otherwise, false. <paramref
/// name="lockTaken"/> must be initialized to false prior to calling this method.</param>
/// <exception cref="T:System.Threading.LockRecursionException">
/// Thread ownership tracking is enabled, and the current thread has already acquired this lock.
/// </exception>
/// <exception cref="T:System.ArgumentException">
/// The <paramref name="lockTaken"/> argument must be initialized to false prior to calling Enter.
/// </exception>
public void Enter(ref bool lockTaken)
{
if (lockTaken)
{
lockTaken = false;
throw new System.ArgumentException(Environment2.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"));
}
// Fast path to acquire the lock if the lock is released
// If the thread tracking enabled set the new owner to the current thread id
// Id not, set the anonymous bit lock
int observedOwner = m_owner;
int newOwner = 0;
bool threadTrackingEnabled = (m_owner & LOCK_ID_DISABLE_MASK) == 0;
if (threadTrackingEnabled)
{
if (observedOwner == LOCK_UNOWNED)
{
newOwner = Thread.CurrentThread.ManagedThreadId;
}
}
else if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
newOwner = observedOwner | LOCK_ANONYMOUS_OWNED; // set the lock bit
}
if (newOwner != 0)
{
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
#endif
#if PFX_LEGACY_3_5
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)
{
lockTaken = true;
return;
}
#else
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
// Fast path succeeded
return;
}
#endif
#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
}
//Fast path failed, try slow path
ContinueTryEnter(Timeout.Infinite, ref lockTaken);
}