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; }