Skip to content

Commit

Permalink
Merge branch 'master' into dev/etan/st-nilreader
Browse files Browse the repository at this point in the history
  • Loading branch information
arnetheduck authored Mar 5, 2024
2 parents 9d595cc + 4ed0cd6 commit d83cf91
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 8 deletions.
17 changes: 11 additions & 6 deletions chronos/internal/asyncfutures.nim
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ template orImpl*[T, Y](fut1: Future[T], fut2: Future[Y]): untyped =
fut2.addCallback(cb)

retFuture.cancelCallback = cancellation
return retFuture
retFuture

proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
## Returns a future which will complete once either ``fut1`` or ``fut2``
Expand All @@ -801,7 +801,7 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
## completed, the result future will also be completed.
##
## If cancelled, ``fut1`` and ``fut2`` futures WILL NOT BE cancelled.
var retFuture = newFuture[void]("chronos.or")
var retFuture = newFuture[void]("chronos.or()")
orImpl(fut1, fut2)


Expand Down Expand Up @@ -1410,6 +1410,8 @@ proc withTimeout*[T](fut: Future[T], timeout: Duration): Future[bool] {.
var
retFuture = newFuture[bool]("chronos.withTimeout",
{FutureFlag.OwnCancelSchedule})
# We set `OwnCancelSchedule` flag, because we going to cancel `retFuture`
# manually at proper time.
moment: Moment
timer: TimerCallback
timeouted = false
Expand Down Expand Up @@ -1536,6 +1538,8 @@ proc wait*[T](fut: Future[T], timeout = InfiniteDuration): Future[T] =
## should return, because it can't be cancelled too.
var
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)

Expand Down Expand Up @@ -1665,10 +1669,9 @@ proc `or`*[T, Y, E1, E2](
fut1: InternalRaisesFuture[T, E1],
fut2: InternalRaisesFuture[Y, E2]): auto =
type
InternalRaisesFutureRaises = union(E1, E2)
InternalRaisesFutureRaises = union(E1, E2).union((CancelledError,))

let
retFuture = newFuture[void]("chronos.wait()", {FutureFlag.OwnCancelSchedule})
let retFuture = newFuture[void]("chronos.or()", {})
orImpl(fut1, fut2)

proc wait*(fut: InternalRaisesFuture, timeout = InfiniteDuration): auto =
Expand All @@ -1678,6 +1681,8 @@ proc wait*(fut: InternalRaisesFuture, timeout = InfiniteDuration): auto =
InternalRaisesFutureRaises = E.prepend(CancelledError, AsyncTimeoutError)

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)
2 changes: 1 addition & 1 deletion chronos/internal/raisesfutures.nim
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ macro union*(tup0: typedesc, tup1: typedesc): typedesc =
if not found:
result.add err

for err2 in getType(getTypeInst(tup1)[1])[1..^1]:
for err2 in tup1.members():
result.add err2
if result.len == 0:
result = makeNoRaises()
Expand Down
13 changes: 13 additions & 0 deletions tests/testbugs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ suite "Asynchronous issues test suite":
await server.closeWait()
return true

proc testOrDeadlock(): Future[bool] {.async.} =
proc f(): Future[void] {.async.} =
await sleepAsync(2.seconds) or sleepAsync(1.seconds)
let fx = f()
try:
await fx.cancelAndWait().wait(2.seconds)
except AsyncTimeoutError:
return false
true

test "Issue #6":
check waitFor(issue6()) == true

Expand All @@ -152,3 +162,6 @@ suite "Asynchronous issues test suite":

test "IndexError crash test":
check waitFor(testIndexError()) == true

test "`or` deadlock [#516] test":
check waitFor(testOrDeadlock()) == true
26 changes: 26 additions & 0 deletions tests/testfut.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1594,6 +1594,19 @@ suite "Future[T] behavior test suite":
discard someFut.tryCancel()
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":
proc testInnerFoo(fooFut: Future[void]): Future[TestFooConnection] {.
async.} =
Expand Down Expand Up @@ -1654,6 +1667,19 @@ suite "Future[T] behavior test suite":
discard someFut.tryCancel()
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":
proc testInnerFoo(fooFut: Future[void]) {.async.} =
await fooFut
Expand Down
2 changes: 1 addition & 1 deletion tests/testmacro.nim
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ suite "Exceptions tracking":
proc testit2 {.async: (raises: [IOError]).} =
raise (ref IOError)()

proc test {.async: (raises: [ValueError, IOError]).} =
proc test {.async: (raises: [CancelledError, ValueError, IOError]).} =
await testit() or testit2()

proc noraises() {.raises: [].} =
Expand Down

0 comments on commit d83cf91

Please sign in to comment.