fix circular reference in timer (#510)

This commit is contained in:
Jacek Sieka 2024-03-07 08:07:53 +01:00 committed by GitHub
parent 03d82475d9
commit c5a5ece487
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 16 additions and 7 deletions

View File

@ -1010,12 +1010,14 @@ else:
retFuture.fail(newException(AsyncProcessError, retFuture.fail(newException(AsyncProcessError,
osErrorMsg(res.error()))) osErrorMsg(res.error())))
timer = nil
proc cancellation(udata: pointer) {.gcsafe.} = proc cancellation(udata: pointer) {.gcsafe.} =
if not(retFuture.finished()): if not(isNil(timer)):
if not(isNil(timer)): clearTimer(timer)
clearTimer(timer) timer = nil
# Ignore any errors because of cancellation. # Ignore any errors because of cancellation.
discard removeProcess2(processHandle) discard removeProcess2(processHandle)
if timeout != InfiniteDuration: if timeout != InfiniteDuration:
timer = setTimer(Moment.fromNow(timeout), continuation, cast[pointer](2)) timer = setTimer(Moment.fromNow(timeout), continuation, cast[pointer](2))

View File

@ -1386,13 +1386,15 @@ proc sleepAsync*(duration: Duration): Future[void] {.
proc completion(data: pointer) {.gcsafe.} = proc completion(data: pointer) {.gcsafe.} =
if not(retFuture.finished()): if not(retFuture.finished()):
retFuture.complete() retFuture.complete()
timer = nil # Release circular reference (for gc:arc)
proc cancellation(udata: pointer) {.gcsafe.} = proc cancellation(udata: pointer) {.gcsafe.} =
if not(retFuture.finished()): if not isNil(timer):
clearTimer(timer) clearTimer(timer)
timer = nil # Release circular reference (for gc:arc)
retFuture.cancelCallback = cancellation retFuture.cancelCallback = cancellation
timer = setTimer(moment, completion, cast[pointer](retFuture)) timer = setTimer(moment, completion)
return retFuture return retFuture
proc sleepAsync*(ms: int): Future[void] {. proc sleepAsync*(ms: int): Future[void] {.
@ -1487,6 +1489,7 @@ proc withTimeout*[T](fut: Future[T], timeout: Duration): Future[bool] {.
if not(isNil(timer)): if not(isNil(timer)):
clearTimer(timer) clearTimer(timer)
fut.completeFuture() fut.completeFuture()
timer = nil
# TODO: raises annotation shouldn't be needed, but likely similar issue as # TODO: raises annotation shouldn't be needed, but likely similar issue as
# https://github.com/nim-lang/Nim/issues/17369 # https://github.com/nim-lang/Nim/issues/17369
@ -1497,6 +1500,7 @@ proc withTimeout*[T](fut: Future[T], timeout: Duration): Future[bool] {.
fut.cancelSoon() fut.cancelSoon()
else: else:
fut.completeFuture() fut.completeFuture()
timer = nil
if fut.finished(): if fut.finished():
retFuture.complete(true) retFuture.complete(true)
@ -1549,6 +1553,7 @@ proc waitImpl[F: SomeFuture](fut: F, retFuture: auto, timeout: Duration): auto =
if not(isNil(timer)): if not(isNil(timer)):
clearTimer(timer) clearTimer(timer)
fut.completeFuture() fut.completeFuture()
timer = nil
var cancellation: proc(udata: pointer) {.gcsafe, raises: [].} var cancellation: proc(udata: pointer) {.gcsafe, raises: [].}
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: else:
fut.completeFuture() fut.completeFuture()
timer = nil
if fut.finished(): if fut.finished():
fut.completeFuture() fut.completeFuture()
else: else: