Repro
<?php
use Async\Future;
use Async\FutureState;
use function Async\spawn;
use function Async\await_all;
$s1 = new FutureState();
$s2 = new FutureState();
$f1 = new Future($s1);
$f2 = new Future($s2);
$P = spawn(fn() => $s2->complete(2)); // completes F2
$A = spawn(fn() => \Async\await_any_or_fail([$f1, $f2]));
await_all([$P, $A]);
Expected: A receives 2, both coroutines finish.
Actual: deadlock. Output:
=== DEADLOCK REPORT START ===
Coroutines waiting: 2, active_events: 0
Coroutine 6 spawned at :0, suspended at repro.php:19 (main)
waiting for: Coroutine 10 ...
Coroutine 10 spawned at repro.php:15, suspended at repro.php:16
waiting for:
If the producer completes the first future ($s1->complete(1)) instead, the test passes — the awaiter wakes up and returns 1. So await_any_or_fail appears to register a listener only on the first trigger of the iterable, ignoring the rest.
Where it was found
fuzzy_tests/await/await_any.feature, Examples row which=F2, deterministic
under FIFO and every random scheduler tested. Found by the chaos harness
introduced in #102.
Repro
Expected: A receives 2, both coroutines finish.
Actual: deadlock. Output:
If the producer completes the first future (
$s1->complete(1)) instead, the test passes — the awaiter wakes up and returns 1. Soawait_any_or_failappears to register a listener only on the first trigger of the iterable, ignoring the rest.Where it was found
fuzzy_tests/await/await_any.feature, Examples rowwhich=F2, deterministicunder FIFO and every random scheduler tested. Found by the chaos harness
introduced in #102.