Run single-threaded V8 dispatches on reusable thread#416
Open
sam-saffron-jarvis wants to merge 1 commit into
Open
Run single-threaded V8 dispatches on reusable thread#416sam-saffron-jarvis wants to merge 1 commit into
sam-saffron-jarvis wants to merge 1 commit into
Conversation
e79cb5d to
eeaa806
Compare
eeaa806 to
b9c1ab0
Compare
b9c1ab0 to
25ba0c0
Compare
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
Fixes
:single_threadedso V8 still uses the single-threaded platform, but MiniRacer no longer runs V8 dispatches directly on the Ruby caller thread.Instead, each context lazily starts a reusable single-threaded V8 runner thread. The important bit: the runner waits outside V8, and only enters V8 for an individual dispatch:
JS→Ruby callbacks rendezvous back to the original Ruby caller thread through the existing condition-variable protocol, so the V8 runner thread does not directly reacquire the GVL or run Ruby code.
This addresses #415. In that workload, the previous same-Ruby-thread
:single_threadedpath could crash during V8 exception unwinding inv8::internal::wasm::StackMemory::jslimit(). The crash appears to depend on the embedding shape where V8 runs on a Ruby thread and callbacks re-enter Ruby/GVL from inside the V8 stack.No extra public option is added.
MiniRacer::Platform.set_flags!(:single_threaded)keeps the existing public API.Fork behavior
This preserves the important historical property of
:single_threaded: an inherited context can still be used afterfork.The reusable runner is tracked per process id. If a context is inherited into a child process, the parent runner thread is gone, so the next dispatch notices the pid change and starts a new runner thread in the child.
The runner does not hold V8's
LockerorIsolate::Scopewhile idle, so the normal idle-at-fork case does not inherit a V8 thread parked inside the isolate.Changes
v8_single_threaded_enter(...)dispatches with a reusable per-context runner thread.v8_roundtrip()use the condition-variable rendezvous path for:single_threadedtoo.Validation
MiniRacer test suite:
Forking smoke test:
Fork stress:
Single-threaded Ruby callback smoke:
Standalone #415 replay now completes with the normal existing flag:
The original Discourse repro from #415 also passes unchanged: