@@ -241,6 +241,12 @@ NODE_MODULE_INIT(/* exports, module, context */) {
241241
242242#### Worker support
243243
244+ In order to be loaded from multiple Node.js environments,
245+ such as a main thread and a Worker thread, an add-on needs to either:
246+
247+ * Be an N-API addon, or
248+ * Be declared as context-aware using ` NODE_MODULE_INIT() ` as described above
249+
244250In order to support [ ` Worker ` ] [ ] threads, addons need to clean up any resources
245251they may have allocated when such a thread exists. This can be achieved through
246252the usage of the ` AddEnvironmentCleanupHook() ` function:
@@ -254,13 +260,62 @@ void AddEnvironmentCleanupHook(v8::Isolate* isolate,
254260This function adds a hook that will run before a given Node.js instance shuts
255261down. If necessary, such hooks can be removed using
256262`RemoveEnvironmentCleanupHook()` before they are run, which has the same
257- signature.
263+ signature. Callbacks are run in last-in first-out order.
258264
259- In order to be loaded from multiple Node.js environments,
260- such as a main thread and a Worker thread, an add-on needs to either:
265+ The following `addon.cc` uses `AddEnvironmentCleanupHook`:
261266
262- * Be an N-API addon, or
263- * Be declared as context-aware using `NODE_MODULE_INIT()` as described above
267+ ```cpp
268+ // addon.cc
269+ #include <assert.h>
270+ #include <stdlib.h>
271+ #include <node.h>
272+
273+ using node::AddEnvironmentCleanupHook;
274+ using v8::HandleScope;
275+ using v8::Isolate;
276+ using v8::Local;
277+ using v8::Object;
278+
279+ // Note: In a real-world application, do not rely on static/global data.
280+ static char cookie[] = "yum yum";
281+ static int cleanup_cb1_called = 0;
282+ static int cleanup_cb2_called = 0;
283+
284+ static void cleanup_cb1(void* arg) {
285+ Isolate* isolate = static_cast<Isolate*>(arg);
286+ HandleScope scope(isolate);
287+ Local<Object> obj = Object::New(isolate);
288+ assert(!obj.IsEmpty()); // assert VM is still alive
289+ assert(obj->IsObject());
290+ cleanup_cb1_called++;
291+ }
292+
293+ static void cleanup_cb2(void* arg) {
294+ assert(arg == static_cast<void*>(cookie));
295+ cleanup_cb2_called++;
296+ }
297+
298+ static void sanity_check(void*) {
299+ assert(cleanup_cb1_called == 1);
300+ assert(cleanup_cb2_called == 1);
301+ }
302+
303+ // Initialize this addon to be context-aware.
304+ NODE_MODULE_INIT(/* exports, module, context */) {
305+ Isolate* isolate = context->GetIsolate();
306+
307+ AddEnvironmentCleanupHook(isolate, sanity_check, nullptr);
308+ AddEnvironmentCleanupHook(isolate, cleanup_cb2, cookie);
309+ AddEnvironmentCleanupHook(isolate, cleanup_cb1, isolate);
310+ }
311+ ```
312+
313+ Test in JavaScript by running:
314+
315+ ``` js
316+ // test.js
317+ require (' ./build/Release/addon' );
318+ ```
264319
265320### Building
266321
@@ -1293,85 +1348,6 @@ console.log(result);
12931348// Prints: 30
12941349```
12951350
1296- ### AtExit hooks
1297-
1298- An ` AtExit ` hook is a function that is invoked after the Node.js event loop
1299- has ended but before the JavaScript VM is terminated and Node.js shuts down.
1300- ` AtExit ` hooks are registered using the ` node::AtExit ` API.
1301-
1302- #### void AtExit(callback, args)
1303-
1304- * ` callback ` <span class =" type " >< ; void (\* )(void\* )> ; </span >
1305- A pointer to the function to call at exit.
1306- * ` args ` <span class =" type " >< ; void\* > ; </span >
1307- A pointer to pass to the callback at exit.
1308-
1309- Registers exit hooks that run after the event loop has ended but before the VM
1310- is killed.
1311-
1312- ` AtExit ` takes two parameters: a pointer to a callback function to run at exit,
1313- and a pointer to untyped context data to be passed to that callback.
1314-
1315- Callbacks are run in last-in first-out order.
1316-
1317- The following ` addon.cc ` implements ` AtExit ` :
1318-
1319- ``` cpp
1320- // addon.cc
1321- #include < assert.h>
1322- #include < stdlib.h>
1323- #include < node.h>
1324-
1325- namespace demo {
1326-
1327- using node::AtExit;
1328- using v8::HandleScope;
1329- using v8::Isolate;
1330- using v8::Local;
1331- using v8::Object;
1332-
1333- static char cookie[ ] = "yum yum";
1334- static int at_exit_cb1_called = 0;
1335- static int at_exit_cb2_called = 0;
1336-
1337- static void at_exit_cb1(void* arg) {
1338- Isolate* isolate = static_cast<Isolate* >(arg);
1339- HandleScope scope(isolate);
1340- Local<Object > obj = Object::New(isolate);
1341- assert(!obj.IsEmpty()); // assert VM is still alive
1342- assert(obj->IsObject());
1343- at_exit_cb1_called++;
1344- }
1345-
1346- static void at_exit_cb2(void* arg) {
1347- assert(arg == static_cast<void* >(cookie));
1348- at_exit_cb2_called++;
1349- }
1350-
1351- static void sanity_check(void* ) {
1352- assert(at_exit_cb1_called == 1);
1353- assert(at_exit_cb2_called == 2);
1354- }
1355-
1356- void init(Local<Object > exports) {
1357- AtExit(sanity_check);
1358- AtExit(at_exit_cb2, cookie);
1359- AtExit(at_exit_cb2, cookie);
1360- AtExit(at_exit_cb1, exports->GetIsolate());
1361- }
1362-
1363- NODE_MODULE(NODE_GYP_MODULE_NAME, init)
1364-
1365- } // namespace demo
1366- ```
1367-
1368- Test in JavaScript by running:
1369-
1370- ```js
1371- // test.js
1372- require('./build/Release/addon');
1373- ```
1374-
13751351[ `Worker`]: worker_threads.html#worker_threads_class_worker
13761352[Electron]: https:// electronjs.org/
13771353[Embedder' s Guide]: https://github.com/v8/v8/wiki/Embedder' s%20Guide
0 commit comments