LCOV - code coverage report
Current view: top level - Cqrs/Infrastructure - SpinWait.cs Hit Total Coverage
Test: doc-coverage.info Lines: 6 8 75.0 %
Date: 2017-07-26

          Line data    Source code
       1             : using System;
       2             : using System.Security.Permissions;
       3             : using System.Threading;
       4             : 
       5             : namespace Cqrs.Infrastructure
       6             : {
       7             :         /// <summary>
       8             :         /// Provides support for spin-based waiting.
       9             :         /// </summary>
      10             :         [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)]
      11             :         public struct SpinWait
      12           1 :         {
      13             :                 /// <summary>
      14             :                 /// A recommended sleep value of 50.
      15             :                 /// </summary>
      16             :                 public const short DefaultSleepInMilliseconds = 50;
      17             : 
      18             :                 internal const int YieldThreshold = 10;
      19             :                 internal const int Sleep0EveryHowManyTimes = 5;
      20             :                 internal const int Sleep1EveryHowManyTimes = 20;
      21             :                 private int _count;
      22             : 
      23             :                 /// <summary>
      24             :                 /// Gets whether the next call to <see cref="M:System.Threading.SpinWait.SpinOnce"/> will yield the processor, triggering a forced context switch.
      25             :                 /// </summary>
      26             :                 /// 
      27             :                 /// <returns>
      28             :                 /// Whether the next call to <see cref="M:System.Threading.SpinWait.SpinOnce"/> will yield the processor, triggering a forced context switch.
      29             :                 /// </returns>
      30             :                 public bool NextSpinWillYield
      31             :                 {
      32             :                         get
      33             :                         {
      34             :                                 if (_count <= 10)
      35             :                                         return Environment.ProcessorCount == 1;
      36             :                                 return true;
      37             :                         }
      38             :                 }
      39             : 
      40             :                 /// <summary>
      41             :                 /// Performs a single spin.
      42             :                 /// </summary>
      43             :                 /// <param name="sleepInMilliseconds">The amount of milliseconds the thread will sleep for.</param>
      44           1 :                 public void SpinOnce(short sleepInMilliseconds = 0)
      45             :                 {
      46             :                         if (NextSpinWillYield)
      47             :                         {
      48             :                                 int num = _count >= 10 ? _count - 10 : _count;
      49             :                                 if (num % Sleep1EveryHowManyTimes == Sleep1EveryHowManyTimes - 1)
      50             :                                         Thread.Sleep(sleepInMilliseconds == 0 ? 1 : sleepInMilliseconds * 2);
      51             :                                 else if (num % Sleep0EveryHowManyTimes == Sleep0EveryHowManyTimes - 1)
      52             :                                         Thread.Sleep(sleepInMilliseconds);
      53             :                                 else
      54             :                                 {
      55             :                                         Thread.Yield();
      56             :                                         if (sleepInMilliseconds >= DefaultSleepInMilliseconds)
      57             :                                                 Thread.Sleep(sleepInMilliseconds / 10);
      58             :                                 }
      59             :                         }
      60             :                         else
      61             :                                 Thread.SpinWait(4 << _count);
      62             :                         _count = _count == int.MaxValue ? 10 : _count + 1;
      63             :                 }
      64             : 
      65             :                 /// <summary>
      66             :                 /// Resets the spin counter.
      67             :                 /// </summary>
      68           1 :                 public void Reset()
      69             :                 {
      70             :                         _count = 0;
      71             :                 }
      72             : 
      73             :                 /// <summary>
      74             :                 /// Spins until the specified condition is satisfied.
      75             :                 /// </summary>
      76             :                 /// <param name="condition">A delegate to be executed over and over until it returns true.</param>
      77             :                 /// <param name="sleepInMilliseconds">The amount of milliseconds the thread will sleep for.</param>
      78             :                 /// <exception cref="T:System.ArgumentNullException">The <paramref name="condition"/> argument is null.</exception>
      79           1 :                 public static void SpinUntil(Func<bool> condition, short sleepInMilliseconds = 0)
      80             :                 {
      81             :                         SpinUntil(condition, -1, sleepInMilliseconds);
      82             :                 }
      83             : 
      84             :                 /// <summary>
      85             :                 /// Spins until the specified condition is satisfied or until the specified timeout is expired.
      86             :                 /// </summary>
      87             :                 /// 
      88             :                 /// <returns>
      89             :                 /// True if the condition is satisfied within the timeout; otherwise, false
      90             :                 /// </returns>
      91             :                 /// <param name="condition">A delegate to be executed over and over until it returns true.</param>
      92             :                 /// <param name="timeout">A <see cref="T:System.TimeSpan"/> that represents the number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely.</param>
      93             :                 /// <param name="sleepInMilliseconds">The amount of milliseconds the thread will sleep for.</param>
      94             :                 /// <exception cref="T:System.ArgumentNullException">The <paramref name="condition"/> argument is null.</exception>
      95             :                 /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="timeout"/> is a negative number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater than <see cref="F:System.Int32.MaxValue"/>.</exception>
      96           1 :                 public static bool SpinUntil(Func<bool> condition, TimeSpan timeout, short sleepInMilliseconds = 0)
      97             :                 {
      98             :                         long num = (long) timeout.TotalMilliseconds;
      99             :                         if (num < -1L || num > int.MaxValue)
     100             :                                 throw new ArgumentOutOfRangeException("timeout", timeout, "SpinWait_SpinUntil_TimeoutWrong");
     101             :                         return SpinUntil(condition, (int) timeout.TotalMilliseconds, sleepInMilliseconds);
     102             :                 }
     103             : 
     104             :                 /// <summary>
     105             :                 /// Spins until the specified condition is satisfied or until the specified timeout is expired.
     106             :                 /// </summary>
     107             :                 /// 
     108             :                 /// <returns>
     109             :                 /// True if the condition is satisfied within the timeout; otherwise, false
     110             :                 /// </returns>
     111             :                 /// <param name="condition">A delegate to be executed over and over until it returns true.</param>
     112             :                 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="F:System.Threading.Timeout.Infinite"/> (-1) to wait indefinitely.</param>
     113             :                 /// <param name="sleepInMilliseconds">The amount of milliseconds the thread will sleep for.</param>
     114             :                 /// <exception cref="T:System.ArgumentNullException">The <paramref name="condition"/> argument is null.</exception>
     115             :                 /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a negative number other than -1, which represents an infinite time-out.</exception>
     116           1 :                 public static bool SpinUntil(Func<bool> condition, int millisecondsTimeout, short sleepInMilliseconds = 0)
     117             :                 {
     118             :                         if (millisecondsTimeout < -1)
     119             :                                 throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, "SpinWait_SpinUntil_TimeoutWrong");
     120             :                         if (condition == null)
     121             :                                 throw new ArgumentNullException("condition", "SpinWait_SpinUntil_ArgumentNull");
     122             :                         uint num = 0U;
     123             :                         if (millisecondsTimeout != 0 && millisecondsTimeout != -1)
     124             :                                 num = TimeoutHelper.GetTime();
     125             :                         SpinWait spinWait = new SpinWait();
     126             :                         while (!condition())
     127             :                         {
     128             :                                 if (millisecondsTimeout == 0)
     129             :                                         return false;
     130             :                                 spinWait.SpinOnce(sleepInMilliseconds);
     131             :                                 if (millisecondsTimeout != -1 && spinWait.NextSpinWillYield && millisecondsTimeout <= (TimeoutHelper.GetTime() - num))
     132             :                                         return false;
     133             :                         }
     134             :                         return true;
     135             :                 }
     136             : 
     137             :                 internal static class TimeoutHelper
     138             :                 {
     139           0 :                         public static uint GetTime()
     140             :                         {
     141             :                                 return (uint)Environment.TickCount;
     142             :                         }
     143             : 
     144           0 :                         public static int UpdateTimeOut(uint startTime, int originalWaitMillisecondsTimeout)
     145             :                         {
     146             :                                 uint num1 = GetTime() - startTime;
     147             :                                 if (num1 > int.MaxValue)
     148             :                                         return 0;
     149             :                                 int num2 = originalWaitMillisecondsTimeout - (int)num1;
     150             :                                 if (num2 <= 0)
     151             :                                         return 0;
     152             :                                 return num2;
     153             :                         }
     154             :                 }
     155             :         }
     156             : }

Generated by: LCOV version 1.10