diff options
Diffstat (limited to 'src/mscorlib/src/System/Threading/SpinLock.cs')
-rw-r--r-- | src/mscorlib/src/System/Threading/SpinLock.cs | 82 |
1 files changed, 44 insertions, 38 deletions
diff --git a/src/mscorlib/src/System/Threading/SpinLock.cs b/src/mscorlib/src/System/Threading/SpinLock.cs index 1d90890d6e..eee73ce2bf 100644 --- a/src/mscorlib/src/System/Threading/SpinLock.cs +++ b/src/mscorlib/src/System/Threading/SpinLock.cs @@ -9,19 +9,14 @@ // 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; -using System.Security.Permissions; + +using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; -using System.Diagnostics; -using System.Diagnostics.Contracts; namespace System.Threading { - /// <summary> /// Provides a mutual exclusion lock primitive where a thread trying to acquire the lock waits in a loop /// repeatedly checking until the lock becomes available. @@ -54,7 +49,6 @@ namespace System.Threading /// concurrently. /// </para> /// </remarks> - [ComVisible(false)] [DebuggerTypeProxy(typeof(SystemThreading_SpinLockDebugView))] [DebuggerDisplay("IsHeld = {IsHeld}")] public struct SpinLock @@ -106,6 +100,14 @@ namespace System.Threading // 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); + success = (result == comparand); + return result; + } + /// <summary> /// Initializes a new instance of the <see cref="T:System.Threading.SpinLock"/> /// structure with the option to track thread IDs to improve debugging. @@ -158,9 +160,8 @@ namespace System.Threading int observedOwner = m_owner; if (lockTaken || //invalid parameter (observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || //thread tracking is enabled or the lock is already acquired - Interlocked.CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) //acquiring the lock failed + CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) //acquiring the lock failed ContinueTryEnter(Timeout.Infinite, ref lockTaken); // Then try the slow path if any of the above conditions is met - } /// <summary> @@ -183,7 +184,22 @@ namespace System.Threading /// </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> @@ -219,7 +235,7 @@ namespace System.Threading if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue) { throw new System.ArgumentOutOfRangeException( - nameof(timeout), timeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange")); + nameof(timeout), timeout, SR.SpinLock_TryEnter_ArgumentOutOfRange); } // Call reliable enter with the int-based timeout milliseconds @@ -254,7 +270,7 @@ namespace System.Threading if (millisecondsTimeout < -1 || //invalid parameter lockTaken || //invalid parameter (observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || //thread tracking is enabled or the lock is already acquired - Interlocked.CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) // acquiring the lock failed + CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) // acquiring the lock failed ContinueTryEnter(millisecondsTimeout, ref lockTaken); // The call the slow pth } @@ -271,13 +287,13 @@ namespace System.Threading if (lockTaken) { lockTaken = false; - throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException")); + throw new System.ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException( - nameof(millisecondsTimeout), millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange")); + nameof(millisecondsTimeout), millisecondsTimeout, SR.SpinLock_TryEnter_ArgumentOutOfRange); } uint startTime = 0; @@ -311,7 +327,7 @@ namespace System.Threading observedOwner = m_owner; if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED) { - if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner) + if (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner) { // Aquired lock return; @@ -331,7 +347,7 @@ namespace System.Threading else //failed to acquire the lock,then try to update the waiters. If the waiters count reached the maximum, jsut break the loop to avoid overflow { if ((observedOwner & WAITERS_MASK) != MAXIMUM_WAITERS) - turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1 ; + turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1; } //***Step 2. Spinning @@ -353,7 +369,7 @@ namespace System.Threading : (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit Debug.Assert((newOwner & WAITERS_MASK) >= 0); - if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner) + if (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner) { return; } @@ -381,7 +397,7 @@ namespace System.Threading : (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit Debug.Assert((newOwner & WAITERS_MASK) >= 0); - if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner) + if (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner) { return; } @@ -431,7 +447,6 @@ namespace System.Threading } spinner.SpinOnce(); } - } /// <summary> @@ -444,11 +459,11 @@ namespace System.Threading int lockUnowned = 0; // We are using thread IDs to mark ownership. Snap the thread ID and check for recursion. // We also must or the ID enablement bit, to ensure we propagate when we CAS it in. - int m_newOwner = Thread.CurrentThread.ManagedThreadId; + int m_newOwner = Environment.CurrentManagedThreadId; if (m_owner == m_newOwner) { // We don't allow lock recursion. - throw new LockRecursionException(Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException")); + throw new LockRecursionException(SR.SpinLock_TryEnter_LockRecursionException); } @@ -457,7 +472,6 @@ namespace System.Threading // Loop until the lock has been successfully acquired or, if specified, the timeout expires. do { - // We failed to get the lock, either from the fast route or the last iteration // and the timeout hasn't expired; spin once and try again. spinner.SpinOnce(); @@ -466,7 +480,7 @@ namespace System.Threading if (m_owner == lockUnowned) { - if (Interlocked.CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned) + if (CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned) { return; } @@ -491,7 +505,6 @@ namespace System.Threading /// <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 @@ -517,15 +530,14 @@ namespace System.Threading /// <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 @@ -545,7 +557,7 @@ namespace System.Threading if (threadTrackingEnabled && !IsHeldByCurrentThread) { throw new System.Threading.SynchronizationLockException( - Environment.GetResourceString("SpinLock_Exit_SynchronizationLockException")); + SR.SpinLock_Exit_SynchronizationLockException); } if (useMemoryBarrier) @@ -554,7 +566,6 @@ namespace System.Threading Interlocked.Exchange(ref m_owner, LOCK_UNOWNED); else Interlocked.Decrement(ref m_owner); - } else { @@ -565,9 +576,7 @@ namespace System.Threading int tmpOwner = m_owner; m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED); } - } - } /// <summary> @@ -575,7 +584,6 @@ namespace System.Threading /// </summary> public bool IsHeld { - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get { if (IsThreadOwnerTrackingEnabled) @@ -601,21 +609,19 @@ namespace System.Threading /// </exception> public bool IsHeldByCurrentThread { - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get { if (!IsThreadOwnerTrackingEnabled) { - throw new InvalidOperationException(Environment.GetResourceString("SpinLock_IsHeldByCurrentThread")); + throw new InvalidOperationException(SR.SpinLock_IsHeldByCurrentThread); } - return ((m_owner & (~LOCK_ID_DISABLE_MASK)) == Thread.CurrentThread.ManagedThreadId); + return ((m_owner & (~LOCK_ID_DISABLE_MASK)) == Environment.CurrentManagedThreadId); } } /// <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; } } |