private void WorkLoop()
        {
            var test = Interlocked.CompareExchange(ref workerState, -1, -1);

            //if (Interlocked.CompareExchange(ref workerState, -1, -1) != WORKER_INIT)
            if (test == WORKER_KILLED)
            {
                throw new InvalidOperationException($"This should not happen! {test}");
            }

            while (Interlocked.CompareExchange(ref workerState, 0, 0) != WORKER_KILLED)
            {
                ExpireTimeouts();
                long newDeadline = CalcNewDeadline();
                var  sleepTime   = newDeadline - time.Elapsed;
                // tick before sleep so that timeout added while sleeping
                // will be delayed by a tick to avoid early wake up.
                Sleep(NanoTime.ToMilliseconds(sleepTime));
                Interlocked.Increment(ref ticked);
            }

            unprocessedTimeouts = new HashSet <TimedCallback>();
            foreach (var slot in slots)
            {
                TimedCallback timeout = null;
                while ((timeout = slot.TryPop()) != null)
                {
                    unprocessedTimeouts.Add(timeout);
                }
            }
            stopBarier.Signal();
        }
 internal void Push(TimedCallback callback)
 {
     do
     {
         callback.Next = Interlocked.CompareExchange(ref first, null, null);
     }while (Interlocked.CompareExchange(ref first, callback, callback.Next) != callback.Next);
 }
        /// <summary>
        /// Reassign callback to higher precision timer slot.
        /// </summary>
        /// <param name="hierarchyIdx"></param>
        /// <param name="tick">lower 8 bits of current tick.</param>
        /// <returns></returns>
        private bool CascadeTimers(int hierarchyIdx, long tick)
        {
            // TODO
            // what if newly added timer has been assigned to cascading slot?

            var slot = new HashedWheelSlot(slots[hierarchyIdx, tick].Clear());

            for (TimedCallback callback = slot.TryPop();
                 callback != null;
                 callback = slot.TryPop())
            {
                ScheduleTimeoutImpl(callback,
                                    callback.RemainingTime(time.Elapsed));
            }

            return(tick == 0);
        }
        /// <summary>
        /// Schedule a new callback with specified timeout in milliseconds.
        /// </summary>
        /// <param name="action">Callback function to be fired when timeout.</param>
        /// <returns>A callback wrapper which allow user to cancel timeout.</returns>
        public TimedCallback ScheduleTimeout(Action action, double milliseconds)
        {
            if (milliseconds < 0)
            {
                throw new ArgumentException("Expiry time cannot be negative.", "timeout");
            }
            CheckTimerState();

            var nanoTimeout   = NanoTime.FromMilliseconds(milliseconds);
            var actualTimeout = time.Elapsed + nanoTimeout;
            var callback      = new TimedCallback(action, actualTimeout, this);

            Interlocked.Increment(ref timeoutsCount);
            Interlocked.Increment(ref activeTimeoutsCount);
            ScheduleTimeoutImpl(callback, actualTimeout);

            return(callback);
        }
        private void ScheduleTimeoutImpl(TimedCallback callback, long nanoseconds)
        {
            // TODO: Should always schedule to next tick
            var             differredTimeout = nanoseconds + TicksInterval;
            var             diff             = ToWheelTicks(differredTimeout);
            var             deadline         = NanoTime.ToMilliseconds(CalculateDeadline());
            var             due = diff + deadline;
            HashedWheelSlot slot;

            if (diff < WHEEL_SIZE)
            {
                var _ = (due & WHEEL_MASK);
                slot = slots[0, due & WHEEL_MASK];
            }
            else if (diff < 1 << (2 * WHEEL_BITS))
            {
                var _ = ((due >> WHEEL_BITS) & WHEEL_MASK);
                slot = slots[1, (due >> WHEEL_BITS) & WHEEL_MASK];
            }
            else if (diff < 1 << (3 * WHEEL_BITS))
            {
                var _ = ((due >> 2 * WHEEL_BITS) & WHEEL_MASK);
                slot = slots[2, (due >> 2 * WHEEL_BITS) & WHEEL_MASK];
            }
            else
            {
                if (diff > 0xffffffff)
                {
                    diff = 0xffffffff;
                    due  = NanoTime.ToMilliseconds(diff + deadline);
                }
                var _ = ((due >> 3 * WHEEL_BITS) & WHEEL_MASK);
                slot = slots[3, (due >> 3 * WHEEL_BITS) & WHEEL_MASK];
            }
            slot.Push(callback);
        }
 internal HashedWheelSlot(TimedCallback firstItem)
 {
     first = firstItem;
 }