diff --git a/chronos/internal/asyncengine.nim b/chronos/internal/asyncengine.nim index 4c872f0c5..943f7ec77 100644 --- a/chronos/internal/asyncengine.nim +++ b/chronos/internal/asyncengine.nim @@ -113,13 +113,15 @@ template processTimersGetTimeout(loop, timeout: untyped) = timeout = (lastFinish - curTime).getAsyncTimestamp() if timeout == 0: - if (len(loop.callbacks) == 0) and (len(loop.idlers) == 0): + if (len(loop.callbacks) == 0) and (len(loop.idlers) == 0) and + (len(loop.ticks) == 0): when defined(windows): timeout = INFINITE else: timeout = -1 else: - if (len(loop.callbacks) != 0) or (len(loop.idlers) != 0): + if (len(loop.callbacks) != 0) or (len(loop.idlers) != 0) or + (len(loop.ticks) != 0): timeout = 0 template processTimers(loop: untyped) = diff --git a/tests/testtime.nim b/tests/testtime.nim index 118a602f6..224aabe7f 100644 --- a/tests/testtime.nim +++ b/tests/testtime.nim @@ -8,6 +8,7 @@ import std/os import unittest2 import ../chronos, ../chronos/timer +import ../chronos/timer {.used.} @@ -127,3 +128,34 @@ suite "Asynchronous timers & steps test suite": check: fut3.completed() == true + + test "Cancellation retry tick does not wait for next timer": + const NextTimerSleep = 500.milliseconds + + let gate = newFuture[void]("cancelAndWait.gate") + var + slept = false + workerFut: Future[void] + + proc cancelWorker(): Future[void] {.async.} = + await gate + await workerFut.cancelAndWait() + + proc worker() {.async.} = + try: + await gate + await sleepAsync(NextTimerSleep) + slept = true + except CancelledError: + discard + + let cancelFut = cancelWorker() + workerFut = worker() + gate.complete() + + while not cancelFut.finished: + poll() + + check: + workerFut.finished + not slept