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,
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))

View File

@ -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: