From 171ad3925c8efd2242bb4eb675725adbac0bac9c Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 31 Jan 2017 23:34:28 -0800 Subject: [PATCH] Synchronize SpinLock with CoreRT (#9244) --- src/mscorlib/corefx/SR.cs | 25 +++++++++++ src/mscorlib/src/System/Threading/SpinLock.cs | 61 ++++++++++++--------------- 2 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/mscorlib/corefx/SR.cs b/src/mscorlib/corefx/SR.cs index 23890e0..5f96a40 100644 --- a/src/mscorlib/corefx/SR.cs +++ b/src/mscorlib/corefx/SR.cs @@ -595,4 +595,29 @@ internal static class SR { get { return Environment.GetResourceString("ArgumentException_ValueTupleLastArgumentNotATuple"); } } + + internal static string SpinLock_TryEnter_ArgumentOutOfRange + { + get { return Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"); } + } + + internal static string SpinLock_TryReliableEnter_ArgumentException + { + get { return Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"); } + } + + internal static string SpinLock_TryEnter_LockRecursionException + { + get { return Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException"); } + } + + internal static string SpinLock_Exit_SynchronizationLockException + { + get { return Environment.GetResourceString("SpinLock_Exit_SynchronizationLockException"); } + } + + internal static string SpinLock_IsHeldByCurrentThread + { + get { return Environment.GetResourceString("SpinLock_IsHeldByCurrentThread"); } + } } diff --git a/src/mscorlib/src/System/Threading/SpinLock.cs b/src/mscorlib/src/System/Threading/SpinLock.cs index aad274d..eee73ce 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 { - /// /// 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. /// /// - [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; + } + /// /// Initializes a new instance of the /// 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 - } /// @@ -197,7 +198,7 @@ namespace System.Threading else { // Lock wasn't held; try to acquire it. - Interlocked.CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken); + CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken); } } @@ -234,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 @@ -269,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 } @@ -286,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; @@ -326,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; @@ -346,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 @@ -368,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; } @@ -396,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; } @@ -446,7 +447,6 @@ namespace System.Threading } spinner.SpinOnce(); } - } /// @@ -459,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); } @@ -472,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(); @@ -481,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; } @@ -506,7 +505,6 @@ namespace System.Threading /// /// Thread ownership tracking is enabled, and the current thread is not the owner of this lock. /// - [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 @@ -532,7 +530,6 @@ namespace System.Threading /// /// Thread ownership tracking is enabled, and the current thread is not the owner of this lock. /// - [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 @@ -560,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) @@ -569,7 +566,6 @@ namespace System.Threading Interlocked.Exchange(ref m_owner, LOCK_UNOWNED); else Interlocked.Decrement(ref m_owner); - } else { @@ -580,9 +576,7 @@ namespace System.Threading int tmpOwner = m_owner; m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED); } - } - } /// @@ -590,7 +584,6 @@ namespace System.Threading /// public bool IsHeld { - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get { if (IsThreadOwnerTrackingEnabled) @@ -616,21 +609,19 @@ namespace System.Threading /// 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); } } /// Gets whether thread ownership tracking is enabled for this instance. public bool IsThreadOwnerTrackingEnabled { - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get { return (m_owner & LOCK_ID_DISABLE_MASK) == 0; } } -- 2.7.4