public bool Wait(int timeoutMs, bool spinWait) { Debug.Assert(timeoutMs >= -1); int spinCount = spinWait ? _spinCount : 0; // Try to acquire the semaphore or // a) register as a spinner if spinCount > 0 and timeoutMs > 0 // b) register as a waiter if there's already too many spinners or spinCount == 0 and timeoutMs > 0 // c) bail out if timeoutMs == 0 and return false Counts counts = _separated._counts; while (true) { Debug.Assert(counts.SignalCount <= _maximumSignalCount); Counts newCounts = counts; if (counts.SignalCount != 0) { newCounts.DecrementSignalCount(); } else if (timeoutMs != 0) { if (spinCount > 0 && newCounts.SpinnerCount < byte.MaxValue) { newCounts.IncrementSpinnerCount(); } else { // Maximum number of spinners reached, register as a waiter instead newCounts.IncrementWaiterCount(); } } Counts countsBeforeUpdate = _separated._counts.InterlockedCompareExchange(newCounts, counts); if (countsBeforeUpdate == counts) { if (counts.SignalCount != 0) { return(true); } if (newCounts.WaiterCount != counts.WaiterCount) { return(WaitForSignal(timeoutMs)); } if (timeoutMs == 0) { return(false); } break; } counts = countsBeforeUpdate; } #if CORECLR && TARGET_UNIX // The PAL's wait subsystem is slower, spin more to compensate for the more expensive wait spinCount *= 2; #endif int processorCount = Environment.ProcessorCount; int spinIndex = processorCount > 1 ? 0 : SpinSleep0Threshold; while (spinIndex < spinCount) { LowLevelSpinWaiter.Wait(spinIndex, SpinSleep0Threshold, processorCount); spinIndex++; // Try to acquire the semaphore and unregister as a spinner counts = _separated._counts; while (counts.SignalCount > 0) { Counts newCounts = counts; newCounts.DecrementSignalCount(); newCounts.DecrementSpinnerCount(); Counts countsBeforeUpdate = _separated._counts.InterlockedCompareExchange(newCounts, counts); if (countsBeforeUpdate == counts) { return(true); } counts = countsBeforeUpdate; } } // Unregister as spinner, and acquire the semaphore or register as a waiter counts = _separated._counts; while (true) { Counts newCounts = counts; newCounts.DecrementSpinnerCount(); if (counts.SignalCount != 0) { newCounts.DecrementSignalCount(); } else { newCounts.IncrementWaiterCount(); } Counts countsBeforeUpdate = _separated._counts.InterlockedCompareExchange(newCounts, counts); if (countsBeforeUpdate == counts) { return(counts.SignalCount != 0 || WaitForSignal(timeoutMs)); } counts = countsBeforeUpdate; } }