Fix `or` deadlock issue. (#517)

* Fix `or` should not create future with OwnCancelSchedule flag set.

* Fix `CancelledError` missing from raises list when both futures has empty raises list.

* Fix macros tests.
This commit is contained in:
Eugene Kabanov 2024-03-05 18:33:46 +02:00 committed by GitHub
parent 5dfa3fd7fa
commit 1eb834a2f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 18 additions and 6 deletions

View File

@ -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``
@ -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)
@ -1665,10 +1665,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 =

View File

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

View File

@ -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: [].} =