From c5a5ece4873373e99b04b778996d7ac1f8791492 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 7 Mar 2024 08:07:53 +0100 Subject: [PATCH] fix circular reference in timer (#510) --- chronos/asyncproc.nim | 12 +++++++----- chronos/internal/asyncfutures.nim | 11 +++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/chronos/asyncproc.nim b/chronos/asyncproc.nim index f008776..572e382 100644 --- a/chronos/asyncproc.nim +++ b/chronos/asyncproc.nim @@ -1010,12 +1010,14 @@ else: retFuture.fail(newException(AsyncProcessError, osErrorMsg(res.error()))) + timer = nil + proc cancellation(udata: pointer) {.gcsafe.} = - if not(retFuture.finished()): - if not(isNil(timer)): - clearTimer(timer) - # Ignore any errors because of cancellation. - discard removeProcess2(processHandle) + if not(isNil(timer)): + clearTimer(timer) + timer = nil + # Ignore any errors because of cancellation. + discard removeProcess2(processHandle) if timeout != InfiniteDuration: timer = setTimer(Moment.fromNow(timeout), continuation, cast[pointer](2)) diff --git a/chronos/internal/asyncfutures.nim b/chronos/internal/asyncfutures.nim index d364dc5..206f89c 100644 --- a/chronos/internal/asyncfutures.nim +++ b/chronos/internal/asyncfutures.nim @@ -1386,13 +1386,15 @@ proc sleepAsync*(duration: Duration): Future[void] {. proc completion(data: pointer) {.gcsafe.} = if not(retFuture.finished()): retFuture.complete() + timer = nil # Release circular reference (for gc:arc) proc cancellation(udata: pointer) {.gcsafe.} = - if not(retFuture.finished()): + if not isNil(timer): clearTimer(timer) + timer = nil # Release circular reference (for gc:arc) retFuture.cancelCallback = cancellation - timer = setTimer(moment, completion, cast[pointer](retFuture)) + timer = setTimer(moment, completion) return retFuture proc sleepAsync*(ms: int): Future[void] {. @@ -1487,6 +1489,7 @@ proc withTimeout*[T](fut: Future[T], timeout: Duration): Future[bool] {. if not(isNil(timer)): clearTimer(timer) fut.completeFuture() + timer = nil # TODO: raises annotation shouldn't be needed, but likely similar issue as # https://github.com/nim-lang/Nim/issues/17369 @@ -1497,6 +1500,7 @@ proc withTimeout*[T](fut: Future[T], timeout: Duration): Future[bool] {. fut.cancelSoon() else: fut.completeFuture() + timer = nil if fut.finished(): retFuture.complete(true) @@ -1549,6 +1553,7 @@ proc waitImpl[F: SomeFuture](fut: F, retFuture: auto, timeout: Duration): auto = if not(isNil(timer)): clearTimer(timer) fut.completeFuture() + timer = nil var cancellation: proc(udata: pointer) {.gcsafe, raises: [].} cancellation = proc(udata: pointer) {.gcsafe, raises: [].} = @@ -1559,6 +1564,8 @@ proc waitImpl[F: SomeFuture](fut: F, retFuture: auto, timeout: Duration): auto = else: fut.completeFuture() + timer = nil + if fut.finished(): fut.completeFuture() else: