Repository navigation
Conversation
Once an async generator has completed, requests queued behind the head
request could stay pending forever:
const it = (async function* () {})();
await it.next();
it.return(1);
it.next(); // never settled
Two places stopped processing the queue early:
- The fulfilled and rejected closures of AsyncGeneratorAwaitReturn must
run AsyncGeneratorDrainQueue after settling the return() request.
js_async_generator_resolve_function() settled the request and returned
without resuming the queue.
- AsyncGeneratorDrainQueue keeps settling next() and throw() requests in
the completed state until it reaches a return() or empties the queue.
js_async_generator_resume_next() left the loop after the first one,
which also stranded next() calls that were queued while the body was
still running.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Once an async generator has completed, requests queued behind the head request can stay pending forever. This shows up when a consumer cancels a stream: a
for awaitloop or a wrapper callsreturn()on an already finished generator while anothernext()orreturn()is still in flight, and the awaiting code never resumes.Reproduction
Node.js prints:
qjsat master prints nothing and exits; the pending promises are simply never settled.Cause
Two places stop processing the queue early:
return()request.js_async_generator_resolve_function()(themagic >= 2branch) settles the request and returns without resuming the queue.next()andthrow()requests in the completed state until it reaches areturn()or empties the queue.js_async_generator_resume_next()jumps todoneafter the first one. This also strandsnext()calls that were queued while the body was still running.The fix calls
js_async_generator_resume_next()after settling in the await-return callback, and continues the loop afternext()/throw()in the completed state. Areturn()still stops the loop while its value is awaited.Tests
tests/async-generator-drain-queue.jscovers single and multiple requests queued behindreturn()(fulfilled and rejected), mixednext()/throw()/return()queues, andnext()calls queued while the body awaits. It checks every result and the settlement order, which matches Node.js. It fails withpromise is pendingon master and with either half of the fix alone, and passes with both.On macOS 15 (Apple clang 17):
make test: same result before and after, apart from the new test. The one failure,test_std.js"second pipe handler was not called", also fails on unmodified master in this environment.make test262(test2625ef1e5723b): 40/82220 errors before and after, all listed intest262_errors.txt; no new or fixed tests.make testunderQJS_ENABLE_ASAN+QJS_ENABLE_UBSAN, and the new test underQJS_ENABLE_GC_STRESS: clean.test262 checks
return()on a completed generator (return-state-completed.js) but not with further requests queued behind it, which is why this was not caught there.