From 497cd51b9fee73dd33f4597476be533ea0452c60 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 1 Sep 2026 00:59:33 +0000 Subject: [PATCH] doc: note that FreeEnvironment() runs a shared event loop The embedder docs say each Environment has exactly one `uv_loop_t` and that an `IsolateData` can be shared between Environments, and `CreateIsolateData()` takes the loop, so several same-thread Environments naturally end up on one loop. Nothing mentions that `FreeEnvironment()` then runs that loop, with JavaScript disallowed on the isolate, until the freed Environment's handles are gone, so the other Environments' callbacks can fire inside it. Document that, and point at it from `FreeEnvironment()` in node.h. Signed-off-by: Shelley Vohr --- doc/api/embedding.md | 10 ++++++++++ src/node.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/doc/api/embedding.md b/doc/api/embedding.md index 0309e1120969..dfb84b49ef9b 100644 --- a/doc/api/embedding.md +++ b/doc/api/embedding.md @@ -93,6 +93,16 @@ to as `node::Environment`. Each `node::Environment` is associated with: that `node::IsolateData` is shared only among `node::Environment`s that use the same `v8::Isolate`, Node.js does not perform this check. +`node::Environment`s that share a `node::IsolateData` also share its +`uv_loop_t`. `node::FreeEnvironment()` runs that loop until the handles of the +`node::Environment` being freed have closed, and JavaScript execution is +disallowed on the whole `v8::Isolate` while it does, so pending timers, I/O +callbacks and thread pool completions that belong to other `node::Environment`s +on the same loop can run inside that call without being able to call into +JavaScript. `node::Environment`s that are freed independently of one another +should each use their own `uv_loop_t` and `node::IsolateData`, or the embedder +should make sure the others have no pending work when one of them is freed. + In order to set up a `v8::Isolate`, an `v8::ArrayBuffer::Allocator` needs to be provided. One possible choice is the default Node.js allocator, which can be created through `node::ArrayBufferAllocator::Create()`. Using the Node.js diff --git a/src/node.h b/src/node.h index e827a46e14dd..7ff87113d7f0 100644 --- a/src/node.h +++ b/src/node.h @@ -838,6 +838,9 @@ NODE_EXTERN v8::MaybeLocal LoadEnvironment( const ModuleData* entry_point, EmbedderPreloadCallback preload = nullptr); +// Runs `env`'s event loop until its handles have closed, with JavaScript +// execution disallowed on the isolate; see doc/api/embedding.md if that loop +// is shared with other Environments. NODE_EXTERN void FreeEnvironment(Environment* env); // Set a callback that is called when process.exit() is called from JS,