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(); }
public void TestDelayTimeoutShouldNotLargerThanSingleTickDuration(int tickInterval, int timeout) { var watch = new ConcurrentStopwatch(); var barrier = new CountdownEvent(1); var timer = new HashedWheelTimer(interval: TimeSpan.FromMilliseconds(tickInterval)); long elapsed = 0; watch.Start(); timer.ScheduleTimeout(() => { Interlocked.Exchange(ref elapsed, watch.Elapsed); barrier.Signal(); }, TimeSpan.FromMilliseconds(timeout)); Assert.True(barrier.Wait(tickInterval * 2 + timeout), $"Elapsed: {NanoTime.ToMilliseconds(elapsed)}, ticks interval: {tickInterval}, timeout: {timeout}."); }
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); }