Repository navigation
Conversation
…Wasm, async GC and node:vm timeout cases
Collaborator
Author
|
Updated 11:28 PM PT - Oct 20th, 2026
❌ @robobun, your commit 5e9dbb0 has 2 failures in
🧪 To try this PR locally: bunx bun-pr 46265That installs a local version of the PR into your bun-46265 --bun |
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.
Fixes #44787
Draft until oven-sh/WebKit#824 lands on its
main.WEBKIT_VERSIONthen moves from the preview tarball to the merged sha. Supersedes #41587 (the same bump for the earlier oven-sh/WebKit#569).Problem
pids.maxorRLIMIT_NPROClimit dies withpanic(main thread): abort() calledas soon as a loop gets hot, on its next GC, onnew WebAssembly.Module, or on anode:vmtimeout. An idle script that polls withsetTimeoutdies too. Node reportsEAGAINand keeps running.WTF::Thread::createhasRELEASE_ASSERT(success)onpthread_createEAGAIN(JITWorklist::enqueue -> wakeThreads -> AutomaticThread::start -> Thread::create). Bun's own spawn paths already reportEAGAIN.Fix
WEBKIT_VERSIONto the preview build of Survive a refused thread: GC helpers, collector, JIT worklist, VMTraps and libpas retry instead of crashing WebKit#824. Thread creation is fallible there (Thread::tryCreate, anAutomaticThreadCondition::StartFailure::Retrypolicy). The JIT and Wasm worklists compile on the calling thread when no compiler thread can start, the GC collector's marking runs on the mutator when no collector thread can start, the VMTraps sender and the deadline timers wait for a thread instead of asserting, and the libpas scavenger retries later.test/js/bun/jsc/thread-limit.test.ts. Four cases underrunuser -u nobody -- prlimit --nproc=1with the concurrent JIT and 4 GC markers on: a hot loop, an async then a sync GC,WebAssembly.validate+new WebAssembly.Module,vm.runInNewContextwith a timeout. Each first proves the limit is in force (spawnSync("true")reportsEAGAIN). All four abort with the currentWEBKIT_VERSION(USE_SYSTEM_BUN=1) and pass with the bump. Alsotest/js/bun/jsc,test/js/bun/wasm,test/js/bun/util/bun-gc.test.ts,test/js/web/workers/worker.test.ts,test/js/node/vm/vm.test.ts.Background
RLIMIT_NPROC, and a cgroup v2pids.maxcounts threads too. Root is exempt fromRLIMIT_NPROC, so the test drops tonobodythroughrunuserand sets the limit withprlimit --nproc. It skips where those are missing.bun -eturns the concurrent JIT off and marks with one thread, so the test setsBUN_JSC_useConcurrentJIT=1andBUN_JSC_numberOfGCMarkers=4to ask for the threads a script run from a file asks for.__wrap_pthread_create(src/jsc/bindings/c-bindings.cpp): it cannot create a thread the OS refuses, a retry only masks a transient limit. Considered turning the concurrent JIT off at startup: it cannot react to a limit reached later, and the collector thread and Wasm worklist are refused the same way. The WTF layer is where every lazy JSC thread converges.Downsides
AutomaticThread::start(a thread start, rare) and one per mutator-conducted concurrent-phase poll inCollector::runConcurrentPhase.VMTraps::tryQueuetakes a lock per trap notify where acall_oncewas. No allocations, no syscalls added. Binary size is not comparable untilWEBKIT_VERSIONpoints at a release build: the preview tarball is built without the release flags.node:vmtimeout is not enforced until a thread can start, andworker.terminate()of optimized code with no calls waits for a later trap.Bun.CPUProfile,--cpu-prof). Still hangs: bun's own thread pool for asyncfs(thread pool: report a pool that cannot spawn any worker instead of hanging #37738) andnew Worker(Worker: throw ERR_WORKER_INIT_FAILED when the OS refuses the thread #41675), separate fixes.Notes
Collectorsplit in WebKit). Survive a refused thread: GC helpers, collector, JIT worklist, VMTraps and libpas retry instead of crashing WebKit#824 carries the WTF shape forward and replaces the recovery design after a review found a hang (a sync request queued behind an in-flight collection) and a plan left inPreparingforever.src/andpackages/only, and the bump lives inscripts/build/deps/webkit.ts, so its fail-before run builds with the fixed WebKit. The proof isUSE_SYSTEM_BUN=1 bun test test/js/bun/jsc/thread-limit.test.ts(4 fail,panic(main thread): abort() called) against the currentWEBKIT_VERSION, andbun bd testwith the bump (4 pass).detect_leaks=0: LeakSanitizer needs a tracer thread at exit.worker.test.tshas twoterminate()tests that take 8 to 17 s in this container on main too, andworker-terminate-lifetime.test.tsreports a 16-bytenode_fs_binding::Bindingleak on main too.no test proof · iteration 0 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/bun/jsc/thread-limit.test.ts