Example #1
0
        /// <summary>
        /// Local helper function, waits on the monitor until the monitor recieves signal or the
        /// timeout is expired
        /// </summary>
        /// <param name="millisecondsTimeout">The maximum timeout</param>
        /// <param name="startTime">The start ticks to calculate the elapsed time</param>
        /// <param name="cancellationToken">The CancellationToken to observe.</param>
        /// <returns>true if the monitor recieved a signal, false if the timeout expired</returns>
        private bool WaitUntilCountOrTimeout(int millisecondsTimeout, uint startTime, CancellationToken cancellationToken)
        {
            int remainingWaitMilliseconds = Timeout.Infinite;

            //Wait on the monitor as long as the count is zero
            while (m_currentCount == 0)
            {
                // If cancelled, we throw. Trying to wait could lead to deadlock.
                cancellationToken.ThrowIfCancellationRequested();

                if (millisecondsTimeout != Timeout.Infinite)
                {
                    remainingWaitMilliseconds = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
                    if (remainingWaitMilliseconds <= 0)
                    {
                        // The thread has expires its timeout
                        return(false);
                    }
                }
                // ** the actual wait **
                if (!m_condition.Wait(remainingWaitMilliseconds))
                {
                    return(false);
                }
            }

            return(true);
        }
Example #2
0
        /// <summary>
        /// ContinueTryEnter for the thread tracking mode enabled
        /// </summary>
        private void ContinueTryEnterWithThreadTracking(int millisecondsTimeout, uint startTime, ref bool lockTaken)
        {
            Contract.Assert(IsThreadOwnerTrackingEnabled);

            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;

            if (m_owner == m_newOwner)
            {
                // We don't allow lock recursion.
                throw new LockRecursionException(Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException"));
            }


            SpinWait spinner = new SpinWait();

            // 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();

                // Test before trying to CAS, to avoid acquiring the line exclusively unnecessarily.

                if (m_owner == lockUnowned)
                {
#if !FEATURE_CORECLR
                    Thread.BeginCriticalRegion();
#endif
#if PFX_LEGACY_3_5
                    if (Interlocked.CompareExchange(ref m_owner, m_newOwner, lockUnowned) == lockUnowned)
                    {
                        lockTaken = true;
                        return;
                    }
#else
                    if (Interlocked.CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned)
                    {
                        return;
                    }
#endif

#if !FEATURE_CORECLR
                    // The thread failed to get the lock, so we don't need to remain in a critical region.
                    Thread.EndCriticalRegion();
#endif
                }
                // Check the timeout.  We only RDTSC if the next spin will yield, to amortize the cost.
                if (millisecondsTimeout == 0 ||
                    (millisecondsTimeout != Timeout.Infinite && spinner.NextSpinWillYield &&
                     TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0))
                {
                    return;
                }
            } while (true);
        }
Example #3
0
        /// <summary>
        /// ContinueTryEnter for the thread tracking mode enabled
        /// </summary>
        private void ContinueTryEnterWithThreadTracking(int millisecondsTimeout, uint startTime, ref bool lockTaken)
        {
            Debug.Assert(IsThreadOwnerTrackingEnabled);

            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 = Environment.CurrentManagedThreadId;

            if (m_owner == m_newOwner)
            {
                // We don't allow lock recursion.
                throw new LockRecursionException(SR.SpinLock_TryEnter_LockRecursionException);
            }


            SpinWait spinner = new SpinWait();

            // 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();

                // Test before trying to CAS, to avoid acquiring the line exclusively unnecessarily.

                if (m_owner == lockUnowned)
                {
                    if (CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned)
                    {
                        return;
                    }
                }
                // Check the timeout.  We only RDTSC if the next spin will yield, to amortize the cost.
                if (millisecondsTimeout == 0 ||
                    (millisecondsTimeout != Timeout.Infinite && spinner.NextSpinWillYield &&
                     TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0))
                {
                    return;
                }
            } while (true);
        }
Example #4
0
        private bool WaitUntilCountOrTimeout(int millisecondsTimeout, uint startTime, CancellationToken cancellationToken)
        {
            int remainingWaitMilliseconds = Timeout.Infinite;

            // Wait on the monitor as long as the count is zero
            while (m_currentCount == 0)
            {
                // If cancelled, we throw. Trying to wait could lead to deadlock.
                cancellationToken.ThrowIfCancellationRequested();

                if (millisecondsTimeout != Timeout.Infinite)
                {
                    remainingWaitMilliseconds = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
                    if (remainingWaitMilliseconds <= 0)
                    {
                        // The thread has expires its timeout
                        return(false);
                    }
                }
                // ** the actual wait **
                bool waitSuccessful = Monitor.Wait(m_lockObjAndDisposed, remainingWaitMilliseconds);

                // This waiter has woken up and this needs to be reflected in the count of waiters pulsed to wake. Since we
                // don't have thread-specific pulse state, there is not enough information to tell whether this thread woke up
                // because it was pulsed. For instance, this thread may have timed out and may have been waiting to reacquire
                // the lock before returning from Monitor.Wait, in which case we don't know whether this thread got pulsed. So
                // in any woken case, decrement the count if possible. As such, timeouts could cause more waiters to wake than
                // necessary.
                if (m_countOfWaitersPulsedToWake != 0)
                {
                    --m_countOfWaitersPulsedToWake;
                }

                if (!waitSuccessful)
                {
                    return(false);
                }
            }

            return(true);
        }
Example #5
0
        // Token: 0x06003DEE RID: 15854 RVA: 0x000E60D4 File Offset: 0x000E42D4
        private bool WaitUntilCountOrTimeout(int millisecondsTimeout, uint startTime, CancellationToken cancellationToken)
        {
            int num = -1;

            while (this.m_currentCount == 0)
            {
                cancellationToken.ThrowIfCancellationRequested();
                if (millisecondsTimeout != -1)
                {
                    num = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
                    if (num <= 0)
                    {
                        return(false);
                    }
                }
                if (!Monitor.Wait(this.m_lockObj, num))
                {
                    return(false);
                }
            }
            return(true);
        }
Example #6
0
        /// <summary>
        /// Blocks the current thread until the current <see cref="ManualResetEventSlim"/> is set, using a
        /// 32-bit signed integer to measure the time interval, while observing a <see
        /// cref="T:System.Threading.CancellationToken"/>.
        /// </summary>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see
        /// cref="Timeout.Infinite"/>(-1) to wait indefinitely.</param>
        /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to
        /// observe.</param>
        /// <returns>true if the <see cref="System.Threading.ManualResetEventSlim"/> was set; otherwise,
        /// false.</returns>
        /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a
        /// negative number other than -1, which represents an infinite time-out.</exception>
        /// <exception cref="T:System.InvalidOperationException">
        /// The maximum number of waiters has been exceeded.
        /// </exception>
        /// <exception cref="T:System.Threading.OperationCanceledException"><paramref
        /// name="cancellationToken"/> was canceled.</exception>
        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            ThrowIfDisposed();
            cancellationToken.ThrowIfCancellationRequested(); // an early convenience check

            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout));
            }

            if (!IsSet)
            {
                if (millisecondsTimeout == 0)
                {
                    // For 0-timeouts, we just return immediately.
                    return(false);
                }


                // We spin briefly before falling back to allocating and/or waiting on a true event.
                uint startTime = 0;
                bool bNeedTimeoutAdjustment  = false;
                int  realMillisecondsTimeout = millisecondsTimeout; //this will be adjusted if necessary.

                if (millisecondsTimeout != Timeout.Infinite)
                {
                    // We will account for time spent spinning, so that we can decrement it from our
                    // timeout.  In most cases the time spent in this section will be negligible.  But
                    // we can't discount the possibility of our thread being switched out for a lengthy
                    // period of time.  The timeout adjustments only take effect when and if we actually
                    // decide to block in the kernel below.

                    startTime = TimeoutHelper.GetTime();
                    bNeedTimeoutAdjustment = true;
                }

                // Spin
                int spinCount = SpinCount;
                var spinner   = new SpinWait();
                while (spinner.Count < spinCount)
                {
                    spinner.SpinOnce(SpinWait.Sleep1ThresholdForSpinBeforeWait);

                    if (IsSet)
                    {
                        return(true);
                    }

                    if (spinner.Count >= 100 && spinner.Count % 10 == 0) // check the cancellation token if the user passed a very large spin count
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                    }
                }

                // Now enter the lock and wait.
                EnsureLockObjectCreated();

                // We must register and deregister the token outside of the lock, to avoid deadlocks.
                using (cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCallback, this))
                {
                    lock (m_lock)
                    {
                        // Loop to cope with spurious wakeups from other waits being canceled
                        while (!IsSet)
                        {
                            // If our token was canceled, we must throw and exit.
                            cancellationToken.ThrowIfCancellationRequested();

                            //update timeout (delays in wait commencement are due to spinning and/or spurious wakeups from other waits being canceled)
                            if (bNeedTimeoutAdjustment)
                            {
                                realMillisecondsTimeout = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
                                if (realMillisecondsTimeout <= 0)
                                {
                                    return(false);
                                }
                            }

                            // There is a race condition that Set will fail to see that there are waiters as Set does not take the lock,
                            // so after updating waiters, we must check IsSet again.
                            // Also, we must ensure there cannot be any reordering of the assignment to Waiters and the
                            // read from IsSet.  This is guaranteed as Waiters{set;} involves an Interlocked.CompareExchange
                            // operation which provides a full memory barrier.
                            // If we see IsSet=false, then we are guaranteed that Set() will see that we are
                            // waiting and will pulse the monitor correctly.

                            Waiters = Waiters + 1;

                            if (IsSet)     //This check must occur after updating Waiters.
                            {
                                Waiters--; //revert the increment.
                                return(true);
                            }

                            // Now finally perform the wait.
                            try
                            {
                                // ** the actual wait **
                                if (!Monitor.Wait(m_lock, realMillisecondsTimeout))
                                {
                                    return(false); //return immediately if the timeout has expired.
                                }
                            }
                            finally
                            {
                                // Clean up: we're done waiting.
                                Waiters = Waiters - 1;
                            }

                            // Now just loop back around, and the right thing will happen.  Either:
                            //     1. We had a spurious wake-up due to some other wait being canceled via a different cancellationToken (rewait)
                            // or  2. the wait was successful. (the loop will break)
                        }
                    }
                }
            } // automatically disposes (and deregisters) the callback

            return(true); //done. The wait was satisfied.
        }
 public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
 {
     this.ThrowIfDisposed();
     cancellationToken.ThrowIfCancellationRequested();
     if (millisecondsTimeout < -1)
     {
         throw new ArgumentOutOfRangeException("millisecondsTimeout");
     }
     if (!this.IsSet)
     {
         if (millisecondsTimeout == 0)
         {
             return(false);
         }
         uint startTime            = 0;
         bool flag                 = false;
         int  millisecondsTimeout1 = millisecondsTimeout;
         if (millisecondsTimeout != -1)
         {
             startTime = TimeoutHelper.GetTime();
             flag      = true;
         }
         int num1      = 10;
         int num2      = 5;
         int num3      = 20;
         int spinCount = this.SpinCount;
         for (int index = 0; index < spinCount; ++index)
         {
             if (this.IsSet)
             {
                 return(true);
             }
             if (index < num1)
             {
                 if (index == num1 / 2)
                 {
                     Thread.Yield();
                 }
                 else
                 {
                     Thread.SpinWait(PlatformHelper.ProcessorCount * (4 << index));
                 }
             }
             else if (index % num3 == 0)
             {
                 Thread.Sleep(1);
             }
             else if (index % num2 == 0)
             {
                 Thread.Sleep(0);
             }
             else
             {
                 Thread.Yield();
             }
             if (index >= 100 && index % 10 == 0)
             {
                 cancellationToken.ThrowIfCancellationRequested();
             }
         }
         this.EnsureLockObjectCreated();
         using (cancellationToken.InternalRegisterWithoutEC(ManualResetEventSlim.s_cancellationTokenCallback, (object)this))
         {
             lock (this.m_lock)
             {
                 while (!this.IsSet)
                 {
                     cancellationToken.ThrowIfCancellationRequested();
                     if (flag)
                     {
                         millisecondsTimeout1 = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
                         if (millisecondsTimeout1 <= 0)
                         {
                             return(false);
                         }
                     }
                     this.Waiters = this.Waiters + 1;
                     if (this.IsSet)
                     {
                         this.Waiters = this.Waiters - 1;
                         return(true);
                     }
                     try
                     {
                         if (!Monitor.Wait(this.m_lock, millisecondsTimeout1))
                         {
                             return(false);
                         }
                     }
                     finally
                     {
                         this.Waiters = this.Waiters - 1;
                     }
                 }
             }
         }
     }
     return(true);
 }
Example #8
0
        /// <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)
        {
            // The fast path doesn't throw any exception, so we have to validate the parameters here
            if (lockTaken)
            {
                lockTaken = false;
                throw new System.ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException);
            }

            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException(
                          "millisecondsTimeout", millisecondsTimeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
            }


            uint startTime = 0;

            if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0)
            {
                startTime = TimeoutHelper.GetTime();
            }

#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, 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 (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
                {
                    return;
                }
            }
            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++)
                {
                    SpinWait.Spin((turn + i) * SPINNING_FACTOR * processFactor);
                    if (processFactor < processorCount)
                    {
                        processFactor++;
                    }
                    observedOwner = m_owner;
                    if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
                    {
                        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 (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
                        {
                            return;
                        }
                    }
                }
            }

            // 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)
                {
                    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 (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
                    {
                        return;
                    }
                }

                if (yieldsoFar % SLEEP_ONE_FREQUENCY == 0)
                {
                    Helpers.Sleep(1);
                }
                else if (yieldsoFar % SLEEP_ZERO_FREQUENCY == 0)
                {
                    Helpers.Sleep(0);
                }
                else
                {
                    SpinWait.Yield();
                }

                if (yieldsoFar % TIMEOUT_CHECK_FREQUENCY == 0)
                {
                    //Check the timeout.
                    if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
                    {
                        DecrementWaiters();
                        return;
                    }
                }

                yieldsoFar++;
            }
        }
Example #9
0
        /// <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 or 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)
        {
            // The fast path doesn't throw any exception, so we have to validate the parameters here
            if (lockTaken)
            {
                lockTaken = false;
                throw new ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException);
            }

            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(millisecondsTimeout), millisecondsTimeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
            }

            uint startTime = 0;

            if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0)
            {
                startTime = TimeoutHelper.GetTime();
            }

            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 availability
            // 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 = _owner;
            if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
            {
                if (CompareExchange(ref _owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
                {
                    // Acquired lock
                    return;
                }

                if (millisecondsTimeout == 0)
                {
                    // Did not acquire lock in CompareExchange and timeout is 0 so fail fast
                    return;
                }
            }
            else if (millisecondsTimeout == 0)
            {
                // Did not acquire lock as owned and timeout is 0 so fail fast
                return;
            }
            else // failed to acquire the lock, then try to update the waiters. If the waiters count reached the maximum, just break the loop to avoid overflow
            {
                if ((observedOwner & WAITERS_MASK) != MAXIMUM_WAITERS)
                {
                    // This can still overflow, but maybe there will never be that many waiters
                    turn = (Interlocked.Add(ref _owner, 2) & WAITERS_MASK) >> 1;
                }
            }

            // lock acquired failed and waiters updated

            // *** Step 2, Spinning and Yielding
            var spinner = new SpinWait();

            if (turn > Environment.ProcessorCount)
            {
                spinner.Count = SpinWait.YieldThreshold;
            }
            while (true)
            {
                spinner.SpinOnce(SLEEP_ONE_FREQUENCY);

                observedOwner = _owner;
                if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
                {
                    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 zero because a previous call of Exit(false) which corrupted the waiters
                           : (observedOwner - 2) | 1;                    // otherwise decrement the waiters and set the lock bit
                    Debug.Assert((newOwner & WAITERS_MASK) >= 0);

                    if (CompareExchange(ref _owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
                    {
                        return;
                    }
                }

                if (spinner.Count % TIMEOUT_CHECK_FREQUENCY == 0)
                {
                    // Check the timeout.
                    if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
                    {
                        DecrementWaiters();
                        return;
                    }
                }
            }
        }
 public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
 {
     this.ThrowIfDisposed();
     cancellationToken.ThrowIfCancellationRequested();
     if (millisecondsTimeout < -1)
     {
         throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout));
     }
     if (!this.IsSet)
     {
         if (millisecondsTimeout == 0)
         {
             return(false);
         }
         uint startTime            = 0;
         bool flag                 = false;
         int  millisecondsTimeout1 = millisecondsTimeout;
         if (millisecondsTimeout != -1)
         {
             startTime = TimeoutHelper.GetTime();
             flag      = true;
         }
         int      spinCount = this.SpinCount;
         SpinWait spinWait  = new SpinWait();
         while (spinWait.Count < spinCount)
         {
             spinWait.SpinOnce(-1);
             if (this.IsSet)
             {
                 return(true);
             }
             if (spinWait.Count >= 100 && spinWait.Count % 10 == 0)
             {
                 cancellationToken.ThrowIfCancellationRequested();
             }
         }
         this.EnsureLockObjectCreated();
         using (cancellationToken.UnsafeRegister(ManualResetEventSlim.s_cancellationTokenCallback, (object)this))
         {
             lock (this.m_lock)
             {
                 while (!this.IsSet)
                 {
                     cancellationToken.ThrowIfCancellationRequested();
                     if (flag)
                     {
                         millisecondsTimeout1 = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
                         if (millisecondsTimeout1 <= 0)
                         {
                             return(false);
                         }
                     }
                     ++this.Waiters;
                     if (this.IsSet)
                     {
                         --this.Waiters;
                         return(true);
                     }
                     try
                     {
                         if (!Monitor.Wait(this.m_lock, millisecondsTimeout1))
                         {
                             return(false);
                         }
                     }
                     finally
                     {
                         --this.Waiters;
                     }
                 }
             }
         }
     }
     return(true);
 }
Example #11
0
        private void ContinueTryEnterWithThreadTracking(int millisecondsTimeout, uint startTime, ref bool lockTaken)
        {
            int comparand       = 0;
            int managedThreadId = Thread.CurrentThread.ManagedThreadId;

            if (this.m_owner == managedThreadId)
            {
                throw new LockRecursionException(Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException"));
            }
            SpinWait spinWait = new SpinWait();

            do
            {
                spinWait.SpinOnce();
                if (this.m_owner == comparand)
                {
                    Thread.BeginCriticalRegion();
                    if (Interlocked.CompareExchange(ref this.m_owner, managedThreadId, comparand, ref lockTaken) == comparand)
                    {
                        break;
                    }
                    Thread.EndCriticalRegion();
                }
            }while (millisecondsTimeout != 0 && (millisecondsTimeout == -1 || !spinWait.NextSpinWillYield || TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) > 0));
        }
Example #12
0
        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();
                    }
                }
            }
        }
 public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
 {
     this.ThrowIfDisposed();
     cancellationToken.ThrowIfCancellationRequested();
     if (millisecondsTimeout < -1)
     {
         throw new ArgumentOutOfRangeException("millisecondsTimeout");
     }
     if (!this.IsSet)
     {
         if (millisecondsTimeout == 0)
         {
             return(false);
         }
         uint startTime = 0U;
         bool flag      = false;
         int  num       = millisecondsTimeout;
         if (millisecondsTimeout != -1)
         {
             startTime = TimeoutHelper.GetTime();
             flag      = true;
         }
         int num2      = 10;
         int num3      = 5;
         int num4      = 20;
         int spinCount = this.SpinCount;
         for (int i = 0; i < spinCount; i++)
         {
             if (this.IsSet)
             {
                 return(true);
             }
             if (i < num2)
             {
                 if (i == num2 / 2)
                 {
                     Thread.Yield();
                 }
                 else
                 {
                     Thread.SpinWait(4 << i);
                 }
             }
             else if (i % num4 == 0)
             {
                 Thread.Sleep(1);
             }
             else if (i % num3 == 0)
             {
                 Thread.Sleep(0);
             }
             else
             {
                 Thread.Yield();
             }
             if (i >= 100 && i % 10 == 0)
             {
                 cancellationToken.ThrowIfCancellationRequested();
             }
         }
         this.EnsureLockObjectCreated();
         using (cancellationToken.InternalRegisterWithoutEC(ManualResetEventSlim.s_cancellationTokenCallback, this))
         {
             object @lock = this.m_lock;
             lock (@lock)
             {
                 while (!this.IsSet)
                 {
                     cancellationToken.ThrowIfCancellationRequested();
                     if (flag)
                     {
                         num = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
                         if (num <= 0)
                         {
                             return(false);
                         }
                     }
                     this.Waiters++;
                     if (this.IsSet)
                     {
                         int waiters = this.Waiters;
                         this.Waiters = waiters - 1;
                         return(true);
                     }
                     try
                     {
                         if (!Monitor.Wait(this.m_lock, num))
                         {
                             return(false);
                         }
                     }
                     finally
                     {
                         this.Waiters--;
                     }
                 }
             }
         }
         return(true);
     }
     return(true);
 }
        // 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();
        }
        // Token: 0x06003D93 RID: 15763 RVA: 0x000E4C34 File Offset: 0x000E2E34
        private void ContinueTryEnterWithThreadTracking(int millisecondsTimeout, uint startTime, ref bool lockTaken)
        {
            int num             = 0;
            int managedThreadId = Thread.CurrentThread.ManagedThreadId;

            if (this.m_owner == managedThreadId)
            {
                throw new LockRecursionException(Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException"));
            }
            SpinWait spinWait = default(SpinWait);

            for (;;)
            {
                spinWait.SpinOnce();
                if (this.m_owner == num)
                {
                    Thread.BeginCriticalRegion();
                    if (Interlocked.CompareExchange(ref this.m_owner, managedThreadId, num, ref lockTaken) == num)
                    {
                        break;
                    }
                    Thread.EndCriticalRegion();
                }
                if (millisecondsTimeout == 0 || (millisecondsTimeout != -1 && spinWait.NextSpinWillYield && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0))
                {
                    return;
                }
            }
        }