Repository navigation
feat(ffi/objc): queue void callbacks from other threads instead of waiting - #115
Open
NathanWalker wants to merge 1 commit into
Open
NathanWalker wants to merge 1 commit into
NathanWalker wants to merge 1 commit into
Conversation
…iting A void callback from another thread whose arguments can be captured is queued to the JS thread and its native caller returns at once. Waiting deadlocks whenever the JS thread is itself blocked on that caller, e.g. a synchronous native call whose completion handler fires on a worker thread. - Only an allowlist of argument types is captured: scalars, classes, selectors, structs without pointer fields (copied), objects (retained) and blocks (copied). Everything else, and any non-void callback or setter, still waits for JS. - A JS error in a queued callback goes through the closure uncaught-error handling, like one on the JS thread; the Objective-C exception that handling raises is logged, since no native caller is left to receive it.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the
|
This was referenced Nov 7, 2026
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.
Stacked on #103 (
feat/napi-desktop-callbacks). Part 2 of the #103 split.Summary
A void callback from a thread other than the JS thread is queued to the JS thread, and its native caller returns at once. Waiting deadlocks whenever the JS thread is itself blocked on that caller, e.g. a synchronous native call whose completion handler fires on a worker thread (VideoToolbox's output handler,
dispatch_group_waiton a group whose block calls into JS).Argument allowlist. Only listed types are captured; everything else waits:
BOOL,unichar, vectors, complex,Class,SELCGRect,CMTime)id, typed objects,NSString)Block_copy'd until the call runsRaw pointers, C strings, C arrays, function pointers and structs containing pointers wait. Non-void callbacks and property setters also wait.
Errors. A JS error in a queued callback goes through the same closure uncaught-error handling as one on the JS thread (
__onUncaughtError, then the logged message). That handling ends by raising an Objective-C exception. With no native caller left to receive it, the exception is logged instead of becoming a fatal process exception.Known limits (also documented in
Closure.mm):AudioBufferList *) are not affected because pointer arguments always wait.CMSampleBufferRefparameters are raw pointers, so that callback still waits.Evidence
macOS 26.6.2 (arm64),
--macos --no-enginebuild, on Node v26.10.0, Deno 2.9.1 and Bun 1.4.2:dispatch_group_waiton a group whose void JS block runs on a workerdispatch_group_async_f(rawvoid *context argument)NSMutableStringargument to a JS method viaperformSelectorInBackground:NativeScriptException__onUncaughtErrorcalled once, later callbacks still runMACOS_TEST_FFI_BACKEND=napi npm run test:macos: tests=714, failures=0, errors=0, skipped=17 (the napi bridge in engine builds; the changed code is Node-API-only, so this checks engine builds are unaffected)Merge Danger
Door: two-way
Blast Radius: Node-API builds, void off-thread callbacks
Native code that relied on a void callback from another thread finishing before the caller continued now sees JS run later, after the caller returns. Callbacks that pass raw pointers (e.g.
BOOL *stop), return a value, or set a property still wait.