Esempio n. 1
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 HOW_MANY_SPIN_BEFORE_YIELD   = 10;
                int HOW_MANY_YIELD_EVERY_SLEEP_0 = 5;
                int HOW_MANY_YIELD_EVERY_SLEEP_1 = 20;

                int spinCount = SpinCount;
                for (int i = 0; i < spinCount; i++)
                {
                    if (IsSet)
                    {
                        return(true);
                    }

                    else if (i < HOW_MANY_SPIN_BEFORE_YIELD)
                    {
                        if (i == HOW_MANY_SPIN_BEFORE_YIELD / 2)
                        {
                            RuntimeThread.Yield();
                        }
                        else
                        {
                            RuntimeThread.SpinWait(PlatformHelper.ProcessorCount * (4 << i));
                        }
                    }
                    else if (i % HOW_MANY_YIELD_EVERY_SLEEP_1 == 0)
                    {
                        RuntimeThread.Sleep(1);
                    }
                    else if (i % HOW_MANY_YIELD_EVERY_SLEEP_0 == 0)
                    {
                        RuntimeThread.Sleep(0);
                    }
                    else
                    {
                        RuntimeThread.Yield();
                    }

                    if (i >= 100 && i % 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 unregister the token outside of the lock, to avoid deadlocks.
                using (cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCallback, this))
                {
                    using (LockHolder.Hold(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 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 (!m_condition.Wait(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 unregisters) the callback

            return(true); //done. The wait was satisfied.
        }
Esempio n. 2
0
 public static bool Yield() => RuntimeThread.Yield();
Esempio n. 3
0
        private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr *pHandles, int numHandles, bool waitAll, int millisecondsTimeout, bool interruptible)
        {
            Debug.Assert(millisecondsTimeout >= -1);

            //
            // In the CLR, we use CoWaitForMultipleHandles to pump messages while waiting in an STA.  In that case, we cannot use WAIT_ALL.
            // That's because the wait would only be satisfied if a message arrives while the handles are signalled.
            //
            if (waitAll)
            {
                if (numHandles == 1)
                {
                    waitAll = false;
                }
                else if (RuntimeThread.GetCurrentApartmentType() == RuntimeThread.ApartmentType.STA)
                {
                    throw new NotSupportedException(SR.NotSupported_WaitAllSTAThread);
                }
            }

            RuntimeThread currentThread = RuntimeThread.CurrentThread;

            currentThread.SetWaitSleepJoinState();

            int result;

            if (RuntimeThread.ReentrantWaitsEnabled)
            {
                Debug.Assert(!waitAll);
                result = RuntimeImports.RhCompatibleReentrantWaitAny(false, millisecondsTimeout, numHandles, pHandles);
            }
            else
            {
                result = (int)Interop.mincore.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll, (uint)millisecondsTimeout, false);
            }

            currentThread.ClearWaitSleepJoinState();

            if (result == WaitHandle.WaitFailed)
            {
                int errorCode = Interop.mincore.GetLastError();
                if (waitAll && errorCode == Interop.Errors.ERROR_INVALID_PARAMETER)
                {
                    // Check for duplicate handles. This is a brute force O(n^2) search, which is intended since the typical
                    // array length is short enough that this would actually be faster than using a hash set. Also, the worst
                    // case is not so bad considering that the array length is limited by
                    // <see cref="WaitHandle.MaxWaitHandles"/>.
                    for (int i = 1; i < numHandles; ++i)
                    {
                        IntPtr handle = pHandles[i];
                        for (int j = 0; j < i; ++j)
                        {
                            if (pHandles[j] == handle)
                            {
                                throw new DuplicateWaitObjectException("waitHandles[" + i + ']');
                            }
                        }
                    }
                }

                ThrowWaitFailedException(errorCode);
            }

            return(result);
        }
Esempio n. 4
0
 public static void Sleep(int millisecondsTimeout) => RuntimeThread.Sleep(millisecondsTimeout);
Esempio n. 5
0
 public static void SpinWait(int iterations) => RuntimeThread.SpinWait(iterations);
Esempio n. 6
0
 internal static void Sleep(int milliseconds)
 {
     RuntimeThread.Sleep(milliseconds);
 }
Esempio n. 7
0
 public static int GetCurrentProcessorId() => RuntimeThread.GetCurrentProcessorId();
            private static void WorkerThreadStart()
            {
                // TODO: Event: Worker Thread Start event
                RuntimeThread currentThread = RuntimeThread.CurrentThread;

                while (true)
                {
                    // TODO: Event:  Worker thread wait event
                    while (s_semaphore.Wait(TimeoutMs))
                    {
                        if (TakeActiveRequest())
                        {
                            Volatile.Write(ref ThreadPoolInstance._separated.lastDequeueTime, Environment.TickCount);
                            if (ThreadPoolWorkQueue.Dispatch())
                            {
                                // If the queue runs out of work for us, we need to update the number of working workers to reflect that we are done working for now
                                RemoveWorkingWorker();
                            }

                            // Reset thread-local state that we control.
                            if (currentThread.Priority != ThreadPriority.Normal)
                            {
                                currentThread.Priority = ThreadPriority.Normal;
                            }

                            CultureInfo.CurrentCulture   = CultureInfo.InstalledUICulture;
                            CultureInfo.CurrentUICulture = CultureInfo.InstalledUICulture;
                        }
                        else
                        {
                            // If we woke up but couldn't find a request, we need to update the number of working workers to reflect that we are done working for now
                            RemoveWorkingWorker();
                        }
                    }

                    ThreadPoolInstance._hillClimbingThreadAdjustmentLock.Acquire();
                    try
                    {
                        // At this point, the thread's wait timed out. We are shutting down this thread.
                        // We are going to decrement the number of exisiting threads to no longer include this one
                        // and then change the max number of threads in the thread pool to reflect that we don't need as many
                        // as we had. Finally, we are going to tell hill climbing that we changed the max number of threads.
                        ThreadCounts counts = ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts);
                        while (true)
                        {
                            if (counts.numExistingThreads == counts.numProcessingWork)
                            {
                                // In this case, enough work came in that this thread should not time out and should go back to work.
                                break;
                            }

                            ThreadCounts newCounts = counts;
                            newCounts.numExistingThreads--;
                            newCounts.numThreadsGoal = Math.Max(ThreadPoolInstance._minThreads, Math.Min(newCounts.numExistingThreads, newCounts.numThreadsGoal));
                            ThreadCounts oldCounts = ThreadCounts.CompareExchangeCounts(ref ThreadPoolInstance._separated.counts, newCounts, counts);
                            if (oldCounts == counts)
                            {
                                HillClimbing.ThreadPoolHillClimber.ForceChange(newCounts.numThreadsGoal, HillClimbing.StateOrTransition.ThreadTimedOut);
                                // TODO: Event:  Worker Thread stop event
                                return;
                            }
                            counts = oldCounts;
                        }
                    }
                    finally
                    {
                        ThreadPoolInstance._hillClimbingThreadAdjustmentLock.Release();
                    }
                }
            }
Esempio n. 9
0
 private static void DispatchCallback(IntPtr instance, IntPtr context, IntPtr work)
 {
     RuntimeThread.InitializeThreadPoolThread();
     Debug.Assert(s_work == work);
     ThreadPoolWorkQueue.Dispatch();
 }
Esempio n. 10
0
        /// <summary>
        /// Obtains all of the corresponding safe wait handles and adds a ref to each. Since the <see cref="SafeWaitHandle"/>
        /// property is publically modifiable, this makes sure that we add and release refs one the same set of safe wait
        /// handles to keep them alive during a multi-wait operation.
        /// </summary>
        private static SafeWaitHandle[] ObtainSafeWaitHandles(
            RuntimeThread currentThread,
            WaitHandle[] waitHandles,
            int numWaitHandles,
            out SafeWaitHandle[] rentedSafeWaitHandles)
        {
            Debug.Assert(currentThread == RuntimeThread.CurrentThread);
            Debug.Assert(waitHandles != null);
            Debug.Assert(numWaitHandles > 0);
            Debug.Assert(numWaitHandles <= MaxWaitHandles);
            Debug.Assert(numWaitHandles <= waitHandles.Length);

            rentedSafeWaitHandles = currentThread.RentWaitedSafeWaitHandleArray(numWaitHandles);
            SafeWaitHandle[] safeWaitHandles = rentedSafeWaitHandles ?? new SafeWaitHandle[numWaitHandles];
            bool             success         = false;

            try
            {
                for (int i = 0; i < numWaitHandles; ++i)
                {
                    WaitHandle waitHandle = waitHandles[i];
                    if (waitHandle == null)
                    {
                        throw new ArgumentNullException("waitHandles[" + i + ']', SR.ArgumentNull_ArrayElement);
                    }

                    SafeWaitHandle safeWaitHandle = waitHandle._waitHandle;
                    if (safeWaitHandle == null)
                    {
                        // Throw ObjectDisposedException for backward compatibility even though it is not be representative of the issue
                        throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
                    }

                    safeWaitHandle.DangerousAddRef();
                    safeWaitHandles[i] = safeWaitHandle;
                }
                success = true;
            }
            finally
            {
                if (!success)
                {
                    for (int i = 0; i < numWaitHandles; ++i)
                    {
                        SafeWaitHandle safeWaitHandle = safeWaitHandles[i];
                        if (safeWaitHandle == null)
                        {
                            break;
                        }
                        safeWaitHandle.DangerousRelease();
                        safeWaitHandles[i] = null;
                    }

                    if (rentedSafeWaitHandles != null)
                    {
                        currentThread.ReturnWaitedSafeWaitHandleArray(rentedSafeWaitHandles);
                    }
                }
            }

            return(safeWaitHandles);
        }
Esempio n. 11
0
        private bool TryAcquireContended(int currentThreadId, int millisecondsTimeout)
        {
            //
            // If we already own the lock, just increment the recursion count.
            //
            if (_owningThreadId == currentThreadId)
            {
                checked { _recursionCount++; }
                return(true);
            }

            //
            // We've already made one lock attempt at this point, so bail early if the timeout is zero.
            //
            if (millisecondsTimeout == 0)
            {
                return(false);
            }

            int spins = 1;

            if (s_maxSpinCount == SpinningNotInitialized)
            {
                s_maxSpinCount = (Environment.ProcessorCount > 1) ? MaxSpinningValue : SpinningDisabled;
            }

            while (true)
            {
                //
                // Try to grab the lock.  We may take the lock here even if there are existing waiters.  This creates the possibility
                // of starvation of waiters, but it also prevents lock convoys from destroying perf.
                // The starvation issue is largely mitigated by the priority boost the OS gives to a waiter when we set
                // the event, after we release the lock.  Eventually waiters will be boosted high enough to preempt this thread.
                //
                int oldState = _state;
                if ((oldState & Locked) == 0 && Interlocked.CompareExchange(ref _state, oldState | Locked, oldState) == oldState)
                {
                    goto GotTheLock;
                }

                //
                // Back off by a factor of 2 for each attempt, up to MaxSpinCount
                //
                if (spins <= s_maxSpinCount)
                {
                    RuntimeThread.SpinWait(spins);
                    spins *= 2;
                }
                else
                {
                    //
                    // We reached our spin limit, and need to wait.  Increment the waiter count.
                    // Note that we do not do any overflow checking on this increment.  In order to overflow,
                    // we'd need to have about 1 billion waiting threads, which is inconceivable anytime in the
                    // forseeable future.
                    //
                    int newState = (oldState + WaiterCountIncrement) & ~WaiterWoken;
                    if (Interlocked.CompareExchange(ref _state, newState, oldState) == oldState)
                    {
                        break;
                    }
                }
            }

            //
            // Now we wait.
            //
            TimeoutTracker timeoutTracker = TimeoutTracker.Start(millisecondsTimeout);
            AutoResetEvent ev             = Event;

            while (true)
            {
                Debug.Assert(_state >= WaiterCountIncrement);

                bool waitSucceeded = ev.WaitOne(timeoutTracker.Remaining);

                while (true)
                {
                    int oldState = _state;
                    Debug.Assert(oldState >= WaiterCountIncrement);

                    // Clear the "waiter woken" bit.
                    int newState = oldState & ~WaiterWoken;

                    if ((oldState & Locked) == 0)
                    {
                        // The lock is available, try to get it.
                        newState |= Locked;
                        newState -= WaiterCountIncrement;

                        if (Interlocked.CompareExchange(ref _state, newState, oldState) == oldState)
                        {
                            goto GotTheLock;
                        }
                    }
                    else if (!waitSucceeded)
                    {
                        // The lock is not available, and we timed out.  We're not going to wait agin.
                        newState -= WaiterCountIncrement;

                        if (Interlocked.CompareExchange(ref _state, newState, oldState) == oldState)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        // The lock is not available, and we didn't time out.  We're going to wait again.
                        if (Interlocked.CompareExchange(ref _state, newState, oldState) == oldState)
                        {
                            break;
                        }
                    }
                }
            }

GotTheLock:
            Debug.Assert((_state | Locked) != 0);
            Debug.Assert(_owningThreadId == 0);
            Debug.Assert(_recursionCount == 0);
            _owningThreadId = currentThreadId;
            return(true);
        }
Esempio n. 12
0
 private static void TimerCallback(IntPtr instance, IntPtr context, IntPtr timer)
 {
     RuntimeThread.InitializeThreadPoolThread();
     Instance.FireNextTimers();
 }
Esempio n. 13
0
 public static void OnThreadExiting(RuntimeThread thread)
 {
     thread.WaitInfo.OnThreadExiting();
 }
Esempio n. 14
0
 internal static void Spin(int iterations)
 {
     RuntimeThread.SpinWait(iterations);
 }
        public static int Wait(
            RuntimeThread currentThread,
            SafeWaitHandle[] safeWaitHandles,
            WaitHandle[] waitHandles,
            int numWaitHandles,
            bool waitForAll,
            int timeoutMilliseconds)
        {
            Debug.Assert(currentThread == RuntimeThread.CurrentThread);
            Debug.Assert(safeWaitHandles != null);
            Debug.Assert(numWaitHandles > 0);
            Debug.Assert(numWaitHandles <= safeWaitHandles.Length);
            Debug.Assert(numWaitHandles <= waitHandles.Length);
            Debug.Assert(numWaitHandles <= WaitHandle.MaxWaitHandles);
            Debug.Assert(timeoutMilliseconds >= -1);

            ThreadWaitInfo waitInfo = currentThread.WaitInfo;

            WaitableObject[] waitableObjects = waitInfo.GetWaitedObjectArray(numWaitHandles);
            bool             success         = false;

            try
            {
                for (int i = 0; i < numWaitHandles; ++i)
                {
                    Debug.Assert(safeWaitHandles[i] != null);
                    WaitableObject waitableObject = HandleManager.FromHandle(safeWaitHandles[i].DangerousGetHandle());
                    if (waitForAll)
                    {
                        /// Check if this is a duplicate, as wait-for-all does not support duplicates. Including the parent
                        /// loop, this becomes a brute force O(n^2) search, which is intended since the typical array length is
                        /// short enough that this would actually be faster than other alternatives. Also, the worst case is not
                        /// so bad considering that the array length is limited by <see cref="WaitHandle.MaxWaitHandles"/>.
                        for (int j = 0; j < i; ++j)
                        {
                            if (waitableObject == waitableObjects[j])
                            {
                                throw new DuplicateWaitObjectException("waitHandles[" + i + ']');
                            }
                        }
                    }

                    waitableObjects[i] = waitableObject;
                }
                success = true;
            }
            finally
            {
                if (!success)
                {
                    for (int i = 0; i < numWaitHandles; ++i)
                    {
                        waitableObjects[i] = null;
                    }
                }
            }

            if (numWaitHandles == 1)
            {
                WaitableObject waitableObject = waitableObjects[0];
                waitableObjects[0] = null;
                return
                    (waitableObject.Wait(waitInfo, timeoutMilliseconds, interruptible: true, prioritize: false)
                        ? 0
                        : WaitHandle.WaitTimeout);
            }

            return
                (WaitableObject.Wait(
                     waitableObjects,
                     numWaitHandles,
                     waitForAll,
                     waitInfo,
                     timeoutMilliseconds,
                     interruptible: true,
                     prioritize: false,
                     waitHandlesForAbandon: waitHandles));
        }
Esempio n. 16
0
 private Thread(RuntimeThread runtimeThread)
 {
     Debug.Assert(runtimeThread != null);
     _runtimeThread = runtimeThread;
 }
Esempio n. 17
0
        public IThread CreateThread(IRuntime runtime, string name, Action<Action> dispatchMethod)
        {
            lock (_lock)
            {
                if (String.IsNullOrWhiteSpace(name))
                {
                    throw new ArgumentNullException(name);
                }
                if (_threadsByName.ContainsKey(name))
                {
                    throw new ArgumentException("Thread already exists: " + name);
                }
                IThread thread;
                if (dispatchMethod == null)
                {
                    thread = new RuntimeThread(name, runtime, _logger, _errorHandler);
                }
                else
                {
                    thread = new ExternalThread(name, runtime, _logger, _errorHandler, dispatchMethod);
                }

                _threadsByName.Add(name, thread);
                return thread;
            }
        }
Esempio n. 18
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(
                          nameof(millisecondsTimeout), millisecondsTimeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
            }

            uint startTime = 0;

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

            if (SpinLockTrace.Enabled)
            {
                SpinLockTrace.SpinLock_FastPathFailed(m_owner);
            }

            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)
                {
                    // Aquired lock
                    return;
                }

                if (millisecondsTimeout == 0)
                {
                    // Did not aquire lock in CompareExchange and timeout is 0 so fail fast
                    return;
                }
            }
            else if (millisecondsTimeout == 0)
            {
                // Did not aquire 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, jsut break the loop to avoid overflow
            {
                if ((observedOwner & WAITERS_MASK) != MAXIMUM_WAITERS)
                {
                    turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1;
                }
            }

            //***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++)
                {
                    RuntimeThread.SpinWait((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
                        Debug.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
                    Debug.Assert((newOwner & WAITERS_MASK) >= 0);

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

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

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

                yieldsoFar++;
            }
        }