Repository navigation
fix(worker): keep the worker isolate alive while terminate() uses it, and let it stop a closing worker - #2067
Conversation
Terminate() read the worker isolate and then interrupted it with no lock, while the worker thread could clear the pointer and dispose that isolate in the same window: a worker that ends through its own close() while its parent calls terminate(), or a parent that terminates its children during its own shutdown. Terminate() now holds a mutex across the read and the use, and the worker thread takes it when it withdraws the isolate, before disposing it.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (5)
Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review. 📝 WalkthroughWalkthroughWorker termination can now proceed after a worker calls ChangesWorker termination after close
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to The change lets terminate() stop a worker that has called close(), and it keeps the isolate alive while terminate() uses it. No concrete merge-blocking risk was found, and a new test covers the close-then-spin case. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. A rabbit watched the worker spin, Comment |
close() only ends the worker once its running callback returns, and terminate() returned early for a closing worker, so a worker that kept running after close() could not be stopped. terminate() now interrupts it like any other running worker.
…spec in its timeout A run where terminate() failed left the worker spinning past the spec. The loop now also checks a stop flag the spec raises in afterEach, the spec gets its own Jasmine timeout with a shorter start deadline, and the start-deadline branch fails through an expectation rather than the fail() global this Jasmine does not provide.
Calling
terminate()on a Worker that is ending on its own at the same moment, for example through its ownclose(), can make the parent thread interrupt the worker's isolate after the worker thread has already disposed it. A parent that terminates its child workers during its own shutdown races the same way. Separately,terminate()cannot stop a worker that calledclose()and kept running, soclose(); while (true) {}spins forever.WorkerWrapper::TerminatereadsworkerIsolate_and then callsTerminateExecution()and the event-loop lookup on it with no lock, whileBackgroundLooperclears the pointer and disposes the isolate during teardown. Nothing makes the worker thread wait for aTerminatethat has already read the pointer.Terminatenow holds a mutex across the read and the use, and the worker thread takes the same mutex when it clears the pointer, before disposing the isolate: a terminate that already read it finishes with it first, and a later one finds null. This is the same fix as NativeScript/ios#478 on iOS.close()only ends the worker once its running callback returns, andTerminatereturned early for a closing worker. It no longer returns early for a closing worker, which matches the iOS runtime, so it interrupts one that is still running.The isolate race window is a few instructions wide, so it has no spec. With a sleep injected between the read and the use, a worker that closes itself while
terminate()runs is already disposed when the parent touches its isolate onmain, and stays alive until the parent is done with this change. The new spec for a worker spinning afterclose()fails onmainand passes here, and the full device suite passes.Summary by CodeRabbit
close()but continue running can now be terminated reliably. This prevents them from continuing background activity after termination is requested.