Repository navigation
Run one V8 fallback foreground task per event-loop checkpoint - #117
Merged
Merged
Conversation
(cherry picked from commit daff275)
The test called EdgeV8Platform::Create(true), a signature from the split stack it came from; main's Create() takes no arguments. The header now says what the admitted bit means for a synchronous provider: it reports a provider task it ran, together with pending provider work, in either checkpoint mode, and runs at most one such task per checkpoint. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
syrusakbary
added a commit
to wasmerio/edgejs
that referenced
this pull request
Oct 25, 2026
Advance the napi submodule from a65e9cb8 to NAPI main at dfc50c75. - wasmerio/napi#113 stops the V8 provider from touching a foreground task after handing it to Edge's enqueue hook. Native Edge crashed in PostTaskCommon (SIGSEGV/SIGBUS) when the hook refused a task during env cleanup, mostly in vm and worker_threads tests at exit. - wasmerio/napi#117 runs at most one fallback foreground task per event loop checkpoint, so self-reposting GC tasks no longer stall the V8 WASIX event loop. The bump also brings wasmerio/napi#87, #88, #90, #91, #92, #103 and #104. Public header changes are comments only. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
syrusakbary
added a commit
that referenced
this pull request
Oct 27, 2026
Brings in the V8 foreground-task fixes (#113, #117) and QuickJS termination (#118, #119). Conflicts were in the QuickJS provider, where this branch moved runtime-wide state onto the agent and removed the switchable current context: - napi_env.cc: main's runtime interrupt handler with this branch's constructor (agent and fixed context). Teardown keeps both the agent's value clearing and the interrupt detach, using the env's context. - napi_function.cc, js_native_api_quickjs.cc: main's termination checks, without the napi_env_context_scope__ this branch removed. - last_exception_is_uncatchable() asks the agent, which now holds the pending exception. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
A V8 foreground task can post its successor while it runs (incremental marking, minor GC jobs).
EdgeV8Platform::PumpPendingForegroundTasksdrained the fallback queue until it was empty, so such a chain could keep one event-loop checkpoint busy, stalling the guest's event loop and streamed responses during GC. This ports the fix from #101 ontomain: each checkpoint runs at most one ready fallback task, and reports when it ran one so the runtime takes another turn instead of waiting.The fallback queue is the one used when no enqueue hook is bound. That is every V8 foreground task under the WASIX bridge, which attaches empty hooks. Native EdgeJS binds the hook, so it rarely reaches this path.
#101 was part 9 of the split of #84 and was closed with its stack. The production change is unchanged from #101 (author Christoph Herzog, kept as the first commit). In #85, the same change cut p95 for a streamed Astro dashboard on Edge from 1,109 ms to 84 ms.
Changes
v8/src/edge_v8_platform.cc,.h:PumpPendingForegroundTasksruns one task (return v8::platform::PumpMessageLoop(...)instead of thewhileloop) and returns whether it ran one.v8/src/unofficial_napi.cc: when a task ran,unofficial_napi_event_loop_checkpointreportshost_tasks_admitted | pending_provider_work. EdgeJS readshost_tasks_admittedas "don't wait on libuv this turn". Without it, EdgeJS stops with "Provider reported pending work without admitting a host task" once its uv loop is idle.include/unofficial_napi.h: documents what the admitted bit means for a synchronous provider (new in this port).tests/src/v8_foreground_checkpoint_test.cc: a standalone process posts a four-task self-reposting chain and checks that each pump advances it by one. The test calledEdgeV8Platform::Create(true), a signature from fix(v8): bound foreground work at each JavaScript checkpoint #101's stack; it now callsCreate()(new in this port).Testing
make test-napi: 98/98 pass.test_35_promiseandforeground_checkpoint_fairnesspass 50 repeats.whileloop (the first pump runs all four tasks) and passes with this change.main(18b0ce9e) built against napimain, with and without this change and Fix use-after-free when handing V8 foreground tasks to the enqueue hook #113 together, on macOS arm64:mainmake test-onlymake test-wasix-v8-onlytest-intl,test-lang,test-wasix-v8-processNotes for reviewers
test_35'sProviderEventLoopCheckpointProcessesMicrotasksexpects no admitted bit from V8. Test fixtures bind no enqueue hook, so a V8 task that happens to be ready at that checkpoint would set it. It didn't flake in 50 repeats.PostTaskCommon. Either can land first.main.🤖 Generated with Claude Code