Ensure that `OwnCancelSchedule` flag will not be removed from `wait()` and `withTimeout()`. (#519)

This commit is contained in:
Eugene Kabanov 2024-03-05 18:34:53 +02:00 committed by GitHub
parent 1eb834a2f9
commit 4ed0cd6be7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 1 deletions

View File

@ -1410,6 +1410,8 @@ proc withTimeout*[T](fut: Future[T], timeout: Duration): Future[bool] {.
var var
retFuture = newFuture[bool]("chronos.withTimeout", retFuture = newFuture[bool]("chronos.withTimeout",
{FutureFlag.OwnCancelSchedule}) {FutureFlag.OwnCancelSchedule})
# We set `OwnCancelSchedule` flag, because we going to cancel `retFuture`
# manually at proper time.
moment: Moment moment: Moment
timer: TimerCallback timer: TimerCallback
timeouted = false timeouted = false
@ -1536,6 +1538,8 @@ proc wait*[T](fut: Future[T], timeout = InfiniteDuration): Future[T] =
## should return, because it can't be cancelled too. ## should return, because it can't be cancelled too.
var var
retFuture = newFuture[T]("chronos.wait()", {FutureFlag.OwnCancelSchedule}) retFuture = newFuture[T]("chronos.wait()", {FutureFlag.OwnCancelSchedule})
# We set `OwnCancelSchedule` flag, because we going to cancel `retFuture`
# manually at proper time.
waitImpl(fut, retFuture, timeout) waitImpl(fut, retFuture, timeout)
@ -1677,6 +1681,8 @@ proc wait*(fut: InternalRaisesFuture, timeout = InfiniteDuration): auto =
InternalRaisesFutureRaises = E.prepend(CancelledError, AsyncTimeoutError) InternalRaisesFutureRaises = E.prepend(CancelledError, AsyncTimeoutError)
let let
retFuture = newFuture[T]("chronos.wait()", {FutureFlag.OwnCancelSchedule}) retFuture = newFuture[T]("chronos.wait()", {OwnCancelSchedule})
# We set `OwnCancelSchedule` flag, because we going to cancel `retFuture`
# manually at proper time.
waitImpl(fut, retFuture, timeout) waitImpl(fut, retFuture, timeout)

View File

@ -1594,6 +1594,19 @@ suite "Future[T] behavior test suite":
discard someFut.tryCancel() discard someFut.tryCancel()
await someFut await someFut
asyncTest "wait() should allow cancellation test (depends on race())":
proc testFoo(): Future[bool] {.async.} =
let
resFut = sleepAsync(2.seconds).wait(3.seconds)
timeFut = sleepAsync(1.seconds)
cancelFut = cancelAndWait(resFut)
discard await race(cancelFut, timeFut)
if cancelFut.finished():
return (resFut.cancelled() and cancelFut.completed())
false
check (await testFoo()) == true
asyncTest "withTimeout() cancellation undefined behavior test #1": asyncTest "withTimeout() cancellation undefined behavior test #1":
proc testInnerFoo(fooFut: Future[void]): Future[TestFooConnection] {. proc testInnerFoo(fooFut: Future[void]): Future[TestFooConnection] {.
async.} = async.} =
@ -1654,6 +1667,19 @@ suite "Future[T] behavior test suite":
discard someFut.tryCancel() discard someFut.tryCancel()
await someFut await someFut
asyncTest "withTimeout() should allow cancellation test (depends on race())":
proc testFoo(): Future[bool] {.async.} =
let
resFut = sleepAsync(2.seconds).withTimeout(3.seconds)
timeFut = sleepAsync(1.seconds)
cancelFut = cancelAndWait(resFut)
discard await race(cancelFut, timeFut)
if cancelFut.finished():
return (resFut.cancelled() and cancelFut.completed())
false
check (await testFoo()) == true
asyncTest "Cancellation behavior test": asyncTest "Cancellation behavior test":
proc testInnerFoo(fooFut: Future[void]) {.async.} = proc testInnerFoo(fooFut: Future[void]) {.async.} =
await fooFut await fooFut