public void Exit() { //This is the fast path for the thread tracking is disabled, otherwise go to the slow path if ((m_owner & LOCK_ID_DISABLE_MASK) == 0) { ExitSlowPath(true); } else { Interlocked.Decrement(ref m_owner); } #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif }
public void ExitReadLock() { ReaderWriterCount lrwc = null; EnterMyLock(); lrwc = GetThreadRWCount(true); if (lrwc == null || lrwc.readercount < 1) { //You have to be holding the read lock to make this call. ExitMyLock(); throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedRead)); } if (fIsReentrant) { if (lrwc.readercount > 1) { lrwc.readercount--; ExitMyLock(); #if !FEATURE_NETCORE Thread.EndCriticalRegion(); #endif // !FEATURE_NETCORE return; } if (Thread.CurrentThread.ManagedThreadId == upgradeLockOwnerId) { fUpgradeThreadHoldingRead = false; } } Debug.Assert(owners > 0, "ReleasingReaderLock: releasing lock and no read lock taken"); --owners; Debug.Assert(lrwc.readercount == 1); lrwc.readercount--; ExitAndWakeUpAppropriateWaiters(); #if !FEATURE_NETCORE Thread.EndCriticalRegion(); #endif // !FEATURE_NETCORE }
public bool TryEnterWriteLock(int millisecondsTimeout) { Thread.BeginCriticalRegion(); bool flag = false; try { flag = this.TryEnterWriteLockCore(millisecondsTimeout); } finally { if (!flag) { Thread.EndCriticalRegion(); } } return(flag); }
public bool TryEnterUpgradeableReadLock(int millisecondsTimeout) { Thread.BeginCriticalRegion(); bool result = false; try { result = TryEnterUpgradeableReadLockCore(millisecondsTimeout); } finally { if (!result) { Thread.EndCriticalRegion(); } } return(result); }
public void ReleaseMutex() { if (Win32Native.ReleaseMutex(safeWaitHandle)) { #if !FEATURE_CORECLR Thread.EndCriticalRegion(); Thread.EndThreadAffinity(); #endif } else { #if FEATURE_CORECLR throw new Exception(Environment.GetResourceString("Arg_SynchronizationLockException")); #else throw new ApplicationException(Environment.GetResourceString("Arg_SynchronizationLockException")); #endif // FEATURE_CORECLR } }
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) { int tmpOwner = m_owner; m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED); } else { ExitSlowPath(useMemoryBarrier); } #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif }
private void MutexCleanupCode(object userData, bool exceptionThrown) { Mutex.MutexCleanupInfo mutexCleanupInfo = (Mutex.MutexCleanupInfo)userData; if (!this.hasThreadAffinity) { if (mutexCleanupInfo.mutexHandle != null && !mutexCleanupInfo.mutexHandle.IsInvalid) { if (mutexCleanupInfo.inCriticalRegion) { Win32Native.ReleaseMutex(mutexCleanupInfo.mutexHandle); } mutexCleanupInfo.mutexHandle.Dispose(); } if (mutexCleanupInfo.inCriticalRegion) { Thread.EndCriticalRegion(); Thread.EndThreadAffinity(); } } }
public void ExitUpgradeableReadLock() { int managedThreadId = Thread.CurrentThread.ManagedThreadId; if (!this.fIsReentrant) { if (managedThreadId != this.upgradeLockOwnerId) { throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedUpgrade")); } this.EnterMyLock(); } else { this.EnterMyLock(); ReaderWriterCount threadRWCount = this.GetThreadRWCount(managedThreadId, true); if (threadRWCount == null) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedUpgrade")); } RecursiveCounts rc = threadRWCount.rc; if (rc.upgradecount < 1) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedUpgrade")); } rc.upgradecount--; if (rc.upgradecount > 0) { this.ExitMyLock(); Thread.EndCriticalRegion(); return; } this.fUpgradeThreadHoldingRead = false; } this.owners--; this.upgradeLockOwnerId = -1; this.ExitAndWakeUpAppropriateWaiters(); Thread.EndCriticalRegion(); }
private bool TryEnterUpgradeableReadLock(TimeoutTracker timeout) { #if !FEATURE_NETCORE Thread.BeginCriticalRegion(); #endif // !FEATURE_NETCORE bool result = false; try { result = TryEnterUpgradeableReadLockCore(timeout); } finally { #if !FEATURE_NETCORE if (!result) { Thread.EndCriticalRegion(); } #endif // !FEATURE_NETCORE } return(result); }
public void ExitWriteLock() { int managedThreadId = Thread.CurrentThread.ManagedThreadId; if (!this.fIsReentrant) { if (managedThreadId != this.writeLockOwnerId) { throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedWrite")); } this.EnterMyLock(); } else { this.EnterMyLock(); ReaderWriterCount threadRWCount = this.GetThreadRWCount(managedThreadId, false); if (threadRWCount == null) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedWrite")); } RecursiveCounts rc = threadRWCount.rc; if (rc.writercount < 1) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedWrite")); } rc.writercount--; if (rc.writercount > 0) { this.ExitMyLock(); Thread.EndCriticalRegion(); return; } } this.ClearWriterAcquired(); this.writeLockOwnerId = -1; this.ExitAndWakeUpAppropriateWaiters(); Thread.EndCriticalRegion(); }
public void ExitReadLock() { int managedThreadId = Thread.CurrentThread.ManagedThreadId; ReaderWriterCount threadRWCount = null; this.EnterMyLock(); threadRWCount = this.GetThreadRWCount(managedThreadId, true); if (!this.fIsReentrant) { if (threadRWCount == null) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedRead")); } } else { if ((threadRWCount == null) || (threadRWCount.readercount < 1)) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedRead")); } if (threadRWCount.readercount > 1) { threadRWCount.readercount--; this.ExitMyLock(); Thread.EndCriticalRegion(); return; } if (managedThreadId == this.upgradeLockOwnerId) { this.fUpgradeThreadHoldingRead = false; } } this.owners--; threadRWCount.readercount--; this.ExitAndWakeUpAppropriateWaiters(); Thread.EndCriticalRegion(); }
public void Exit(bool useMemoryBarrier) { if (IsThreadOwnerTrackingEnabled && !IsHeldByCurrentThread) { throw new System.Threading.SynchronizationLockException( Environment2.GetResourceString("SpinLock_Exit_SynchronizationLockException")); } if (useMemoryBarrier) { if (IsThreadOwnerTrackingEnabled) { Interlocked.Exchange(ref m_owner, LOCK_UNOWNED); } else { Interlocked.Decrement(ref m_owner); } } else { if (IsThreadOwnerTrackingEnabled) { m_owner = LOCK_UNOWNED; } else { int tmpOwner = m_owner; Contract.Assert((tmpOwner & LOCK_ANONYMOUS_OWNED) == LOCK_ANONYMOUS_OWNED, "The lock is not held."); m_owner = tmpOwner - 1; } } #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif }
public void TryEnter(int millisecondsTimeout, ref bool lockTaken) { if (lockTaken) { lockTaken = false; throw new ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException")); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange")); } int owner = this.m_owner; int managedThreadId = 0; if (this.IsThreadOwnerTrackingEnabled) { if (owner == 0) { managedThreadId = Thread.CurrentThread.ManagedThreadId; } } else if ((owner & 1) == 0) { managedThreadId = owner | 1; } if (managedThreadId != 0) { Thread.BeginCriticalRegion(); if (Interlocked.CompareExchange(ref this.m_owner, managedThreadId, owner, ref lockTaken) == owner) { return; } Thread.EndCriticalRegion(); } this.ContinueTryEnter(millisecondsTimeout, ref lockTaken); }
private void MutexCleanupCode(Object userData, bool exceptionThrown) { MutexCleanupInfo cleanupInfo = (MutexCleanupInfo)userData; // If hasThreadAffinity isn’t true, we’ve thrown an exception in the above try, and we must free the mutex // on this OS thread before ending our thread affninity. if (!hasThreadAffinity) { if (cleanupInfo.mutexHandle != null && !cleanupInfo.mutexHandle.IsInvalid) { if (cleanupInfo.inCriticalRegion) { Win32Native.ReleaseMutex(cleanupInfo.mutexHandle); } cleanupInfo.mutexHandle.Dispose(); } if (cleanupInfo.inCriticalRegion) { Thread.EndCriticalRegion(); Thread.EndThreadAffinity(); } } }
// Token: 0x06003D91 RID: 15761 RVA: 0x000E49DC File Offset: 0x000E2BDC private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken) { Thread.EndCriticalRegion(); if (lockTaken) { lockTaken = false; throw new ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException")); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange")); } uint startTime = 0U; if (millisecondsTimeout != -1 && millisecondsTimeout != 0) { startTime = TimeoutHelper.GetTime(); } if (CdsSyncEtwBCLProvider.Log.IsEnabled()) { CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(this.m_owner); } if (this.IsThreadOwnerTrackingEnabled) { this.ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTime, ref lockTaken); return; } int num = int.MaxValue; int owner = this.m_owner; if ((owner & 1) == 0) { Thread.BeginCriticalRegion(); if (Interlocked.CompareExchange(ref this.m_owner, owner | 1, owner, ref lockTaken) == owner) { return; } Thread.EndCriticalRegion(); } else if ((owner & 2147483646) != SpinLock.MAXIMUM_WAITERS) { num = (Interlocked.Add(ref this.m_owner, 2) & 2147483646) >> 1; } if (millisecondsTimeout == 0 || (millisecondsTimeout != -1 && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)) { this.DecrementWaiters(); return; } int processorCount = PlatformHelper.ProcessorCount; if (num < processorCount) { int num2 = 1; for (int i = 1; i <= num * 100; i++) { Thread.SpinWait((num + i) * 100 * num2); if (num2 < processorCount) { num2++; } owner = this.m_owner; if ((owner & 1) == 0) { Thread.BeginCriticalRegion(); int value = ((owner & 2147483646) == 0) ? (owner | 1) : (owner - 2 | 1); if (Interlocked.CompareExchange(ref this.m_owner, value, owner, ref lockTaken) == owner) { return; } Thread.EndCriticalRegion(); } } } if (millisecondsTimeout != -1 && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0) { this.DecrementWaiters(); return; } int num3 = 0; for (;;) { owner = this.m_owner; if ((owner & 1) == 0) { Thread.BeginCriticalRegion(); int value2 = ((owner & 2147483646) == 0) ? (owner | 1) : (owner - 2 | 1); if (Interlocked.CompareExchange(ref this.m_owner, value2, owner, ref lockTaken) == owner) { break; } Thread.EndCriticalRegion(); } if (num3 % 40 == 0) { Thread.Sleep(1); } else if (num3 % 10 == 0) { Thread.Sleep(0); } else { Thread.Yield(); } if (num3 % 10 == 0 && millisecondsTimeout != -1 && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0) { goto Block_26; } num3++; } return; Block_26: this.DecrementWaiters(); }
/// <summary> /// Try acquire the lock with long path, this is usually called after the first path in Enter and /// TryEnter failed The reason for short path is to make it inline in the run time which improves the /// performance. This method assumed that the parameter are validated in Enter ir TryENter method /// </summary> /// <param name="millisecondsTimeout">The timeout milliseconds</param> /// <param name="lockTaken">The lockTaken param</param> private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken) { long startTicks = 0; if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0) { startTicks = DateTime.UtcNow.Ticks; } #if !FEATURE_PAL && !FEATURE_CORECLR // PAL doesn't support eventing, and we don't compile CDS providers for Coreclr if (CdsSyncEtwBCLProvider.Log.IsEnabled()) { CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(m_owner); } #endif if (IsThreadOwnerTrackingEnabled) { // Slow path for enabled thread tracking mode ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTicks, ref lockTaken); return; } // then thread tracking is disabled // In this case there are three ways to acquire the lock // 1- the first way the thread either tries to get the lock if it's free or updates the waiters, if the turn >= the processors count then go to 3 else go to 2 // 2- In this step the waiter threads spins and tries to acquire the lock, the number of spin iterations and spin count is dependent on the thread turn // the late the thread arrives the more it spins and less frequent it check the lock avilability // Also the spins count is increaes each iteration // If the spins iterations finished and failed to acquire the lock, go to step 3 // 3- This is the yielding step, there are two ways of yielding Thread.Yield and Sleep(1) // If the timeout is expired in after step 1, we need to decrement the waiters count before returning int observedOwner; //***Step 1, take the lock or update the waiters // try to acquire the lock directly if possoble or update the waiters count SpinWait spinner = new SpinWait(); while (true) { observedOwner = m_owner; if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED) { #if !FEATURE_CORECLR Thread.BeginCriticalRegion(); #endif #if PFX_LEGACY_3_5 if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner) == observedOwner) { lockTaken = true; return; } #else if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner) { return; } #endif #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif } 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 || Interlocked.CompareExchange(ref m_owner, observedOwner + 2, observedOwner) == observedOwner) { break; } spinner.SpinOnce(); } // Check the timeout. if (millisecondsTimeout == 0 || (millisecondsTimeout != Timeout.Infinite && TimeoutExpired(startTicks, millisecondsTimeout))) { DecrementWaiters(); return; } //***Step 2. Spinning //lock acquired failed and waiters updated int turn = ((observedOwner + 2) & WAITERS_MASK) / 2; int processorCount = PlatformHelper.ProcessorCount; if (turn < processorCount) { int processFactor = 1; for (int i = 1; i <= turn * SPINNING_FACTOR; i++) { Thread.SpinWait((turn + i) * SPINNING_FACTOR * processFactor); if (processFactor < processorCount) { processFactor++; } observedOwner = m_owner; if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED) { #if !FEATURE_CORECLR Thread.BeginCriticalRegion(); #endif int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters : (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit Contract.Assert((newOwner & WAITERS_MASK) >= 0); #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) { return; } #endif #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif } } } // Check the timeout. if (millisecondsTimeout != Timeout.Infinite && TimeoutExpired(startTicks, millisecondsTimeout)) { DecrementWaiters(); return; } //*** Step 3, Yielding //Sleep(1) every 50 yields int yieldsoFar = 0; while (true) { observedOwner = m_owner; if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED) { #if !FEATURE_CORECLR Thread.BeginCriticalRegion(); #endif int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters : (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit Contract.Assert((newOwner & WAITERS_MASK) >= 0); #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) { return; } #endif #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif } if (yieldsoFar % SLEEP_ONE_FREQUENCY == 0) { Thread.Sleep(1); } else if (yieldsoFar % SLEEP_ZERO_FREQUENCY == 0) { Thread.Sleep(0); } else { #if PFX_LEGACY_3_5 Platform.Yield(); #else Thread.Yield(); #endif } if (yieldsoFar % TIMEOUT_CHECK_FREQUENCY == 0) { //Check the timeout. if (millisecondsTimeout != Timeout.Infinite && TimeoutExpired(startTicks, millisecondsTimeout)) { DecrementWaiters(); return; } } yieldsoFar++; } }
private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken) { int owner; long startTicks = 0L; if ((millisecondsTimeout != -1) && (millisecondsTimeout != 0)) { startTicks = DateTime.UtcNow.Ticks; } if (CdsSyncEtwBCLProvider.Log.IsEnabled()) { CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(this.m_owner); } if (this.IsThreadOwnerTrackingEnabled) { this.ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTicks, ref lockTaken); return; } SpinWait wait = new SpinWait(); while (true) { owner = this.m_owner; if ((owner & 1) == 0) { Thread.BeginCriticalRegion(); if (Interlocked.CompareExchange(ref this.m_owner, owner | 1, owner, ref lockTaken) == owner) { return; } Thread.EndCriticalRegion(); } else if (((owner & 0x7ffffffe) == MAXIMUM_WAITERS) || (Interlocked.CompareExchange(ref this.m_owner, owner + 2, owner) == owner)) { break; } wait.SpinOnce(); } if ((millisecondsTimeout == 0) || ((millisecondsTimeout != -1) && TimeoutExpired(startTicks, millisecondsTimeout))) { this.DecrementWaiters(); return; } int num3 = ((owner + 2) & 0x7ffffffe) / 2; int processorCount = PlatformHelper.ProcessorCount; if (num3 < processorCount) { int num5 = 1; for (int i = 1; i <= (num3 * 100); i++) { Thread.SpinWait(((num3 + i) * 100) * num5); if (num5 < processorCount) { num5++; } owner = this.m_owner; if ((owner & 1) == 0) { Thread.BeginCriticalRegion(); int num7 = ((owner & 0x7ffffffe) == 0) ? (owner | 1) : ((owner - 2) | 1); if (Interlocked.CompareExchange(ref this.m_owner, num7, owner, ref lockTaken) == owner) { return; } Thread.EndCriticalRegion(); } } } if ((millisecondsTimeout != -1) && TimeoutExpired(startTicks, millisecondsTimeout)) { this.DecrementWaiters(); return; } int num8 = 0; Label_015F: owner = this.m_owner; if ((owner & 1) == 0) { Thread.BeginCriticalRegion(); int num9 = ((owner & 0x7ffffffe) == 0) ? (owner | 1) : ((owner - 2) | 1); if (Interlocked.CompareExchange(ref this.m_owner, num9, owner, ref lockTaken) == owner) { return; } Thread.EndCriticalRegion(); } if ((num8 % 40) == 0) { Thread.Sleep(1); } else if ((num8 % 10) == 0) { Thread.Sleep(0); } else { Thread.Yield(); } if ((((num8 % 10) == 0) && (millisecondsTimeout != -1)) && TimeoutExpired(startTicks, millisecondsTimeout)) { this.DecrementWaiters(); } else { num8++; goto Label_015F; } }
private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken) { Thread.EndCriticalRegion(); if (lockTaken) { lockTaken = false; throw new ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException")); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout", (object)millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange")); } uint startTime = 0; if (millisecondsTimeout != -1 && millisecondsTimeout != 0) { startTime = TimeoutHelper.GetTime(); } if (CdsSyncEtwBCLProvider.Log.IsEnabled()) { CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(this.m_owner); } if (this.IsThreadOwnerTrackingEnabled) { this.ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTime, ref lockTaken); } else { int num1 = int.MaxValue; int comparand1 = this.m_owner; if ((comparand1 & 1) == 0) { Thread.BeginCriticalRegion(); if (Interlocked.CompareExchange(ref this.m_owner, comparand1 | 1, comparand1, ref lockTaken) == comparand1) { return; } Thread.EndCriticalRegion(); } else if ((comparand1 & 2147483646) != SpinLock.MAXIMUM_WAITERS) { num1 = (Interlocked.Add(ref this.m_owner, 2) & 2147483646) >> 1; } if (millisecondsTimeout == 0 || millisecondsTimeout != -1 && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0) { this.DecrementWaiters(); } else { int processorCount = PlatformHelper.ProcessorCount; if (num1 < processorCount) { int num2 = 1; for (int index = 1; index <= num1 * 100; ++index) { Thread.SpinWait((num1 + index) * 100 * num2); if (num2 < processorCount) { ++num2; } int comparand2 = this.m_owner; if ((comparand2 & 1) == 0) { Thread.BeginCriticalRegion(); if (Interlocked.CompareExchange(ref this.m_owner, (comparand2 & 2147483646) == 0 ? comparand2 | 1 : comparand2 - 2 | 1, comparand2, ref lockTaken) == comparand2) { return; } Thread.EndCriticalRegion(); } } } if (millisecondsTimeout != -1 && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0) { this.DecrementWaiters(); } else { int num2 = 0; while (true) { int comparand2 = this.m_owner; if ((comparand2 & 1) == 0) { Thread.BeginCriticalRegion(); if (Interlocked.CompareExchange(ref this.m_owner, (comparand2 & 2147483646) == 0 ? comparand2 | 1 : comparand2 - 2 | 1, comparand2, ref lockTaken) != comparand2) { Thread.EndCriticalRegion(); } else { break; } } if (num2 % 40 == 0) { Thread.Sleep(1); } else if (num2 % 10 == 0) { Thread.Sleep(0); } else { Thread.Yield(); } if (num2 % 10 != 0 || millisecondsTimeout == -1 || TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) > 0) { ++num2; } else { goto label_40; } } return; label_40: this.DecrementWaiters(); } } } }
/// <summary> /// Try acquire the lock with long path, this is usually called after the first path in Enter and /// TryEnter failed The reason for short path is to make it inline in the run time which improves the /// performance. This method assumed that the parameter are validated in Enter ir TryENter method /// </summary> /// <param name="millisecondsTimeout">The timeout milliseconds</param> /// <param name="lockTaken">The lockTaken param</param> private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken) { //Leave the critical region which is entered by the fast path #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif // The fast path doesn't throw any exception, so we have to validate the parameters here if (lockTaken) { lockTaken = false; throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException")); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException( "millisecondsTimeout", millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange")); } uint startTime = 0; if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0) { startTime = TimeoutHelper.GetTime(); } #if !FEATURE_CORECLR if (CdsSyncEtwBCLProvider.Log.IsEnabled()) { CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(m_owner); } #endif if (IsThreadOwnerTrackingEnabled) { // Slow path for enabled thread tracking mode ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTime, ref lockTaken); return; } // then thread tracking is disabled // In this case there are three ways to acquire the lock // 1- the first way the thread either tries to get the lock if it's free or updates the waiters, if the turn >= the processors count then go to 3 else go to 2 // 2- In this step the waiter threads spins and tries to acquire the lock, the number of spin iterations and spin count is dependent on the thread turn // the late the thread arrives the more it spins and less frequent it check the lock avilability // Also the spins count is increases each iteration // If the spins iterations finished and failed to acquire the lock, go to step 3 // 3- This is the yielding step, there are two ways of yielding Thread.Yield and Sleep(1) // If the timeout is expired in after step 1, we need to decrement the waiters count before returning int observedOwner; int turn = int.MaxValue; //***Step 1, take the lock or update the waiters // try to acquire the lock directly if possible or update the waiters count observedOwner = m_owner; if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED) { #if !FEATURE_CORECLR Thread.BeginCriticalRegion(); #endif if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner) { return; } #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif } 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; } } // Check the timeout. if (millisecondsTimeout == 0 || (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)) { DecrementWaiters(); return; } //***Step 2. Spinning //lock acquired failed and waiters updated int processorCount = PlatformHelper.ProcessorCount; if (turn < processorCount) { int processFactor = 1; for (int i = 1; i <= turn * SPINNING_FACTOR; i++) { Thread.SpinWait((turn + i) * SPINNING_FACTOR * processFactor); if (processFactor < processorCount) { processFactor++; } observedOwner = m_owner; if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED) { #if !FEATURE_CORECLR Thread.BeginCriticalRegion(); #endif int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters : (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit Contract.Assert((newOwner & WAITERS_MASK) >= 0); if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner) { return; } #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif } } } // Check the timeout. if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0) { DecrementWaiters(); return; } //*** Step 3, Yielding //Sleep(1) every 50 yields int yieldsoFar = 0; while (true) { observedOwner = m_owner; if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED) { #if !FEATURE_CORECLR Thread.BeginCriticalRegion(); #endif int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters : (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit Contract.Assert((newOwner & WAITERS_MASK) >= 0); if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner) { return; } #if !FEATURE_CORECLR Thread.EndCriticalRegion(); #endif } if (yieldsoFar % SLEEP_ONE_FREQUENCY == 0) { Thread.Sleep(1); } else if (yieldsoFar % SLEEP_ZERO_FREQUENCY == 0) { Thread.Sleep(0); } else { Thread.Yield(); } if (yieldsoFar % TIMEOUT_CHECK_FREQUENCY == 0) { //Check the timeout. if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0) { DecrementWaiters(); return; } } yieldsoFar++; } }