-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Open
Labels
node native extensionrelated to the node-api (.node)related to the node-api (.node)
Description
Summary
uv_async_send spawns work to the main thread via async_work_sender.spawn() without calling ref_op()/unref_op() to keep the event loop alive. This differs from real libuv behavior where an active uv_async_t handle keeps the loop running until uv_close is called.
Current behavior
// ext/napi/uv.rs
unsafe extern "C" fn uv_async_send(handle: *mut uv_async_t) -> c_int {
unsafe {
let env = &mut *(*handle).r#loop;
let handle = SendPtr(handle as *const uv_async_t);
env.async_work_sender.spawn(move |_| {
let handle = handle.take() as *mut uv_async_t;
((*handle).async_cb)(handle);
});
}
0
}No tracker.ref_op() before spawn or tracker.unref_op() after callback completion.
Expected behavior
In libuv, uv_async_init starts the handle immediately and keeps the event loop alive until uv_close is called. The Deno implementation should either:
- Add
ref_op()/unref_op()around the spawned callback (likenapi_queue_async_workdoes), or - Ref the event loop in
uv_async_initand unref inuv_close
Impact
If uv_async_send is called when nothing else keeps the event loop alive, the callback could be silently dropped. This is likely rare in practice since typical usage patterns have other things keeping the loop alive.
Related
- fix(ext/napi): run async work execute callback on a worker thread #32560 added proper ref counting to
napi_queue_async_workbutuv_async_sendwas intentionally changed to spawn directly (since it needs main thread access for V8) - libuv docs: https://docs.libuv.org/en/v1.x/async.html
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
node native extensionrelated to the node-api (.node)related to the node-api (.node)