| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 455a643 commit 60ac18c
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -241,6 +241,12 @@ NODE_MODULE_INIT(/* exports, module, context */) { | |||
| 241 | 241 | ||
| 242 | 242 | #### Worker support | |
| 243 | 243 | ||
| 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 | + | ||
| 244 | 250 | In order to support [`Worker`][] threads, addons need to clean up any resources | |
| 245 | 251 | they may have allocated when such a thread exists. This can be achieved through | |
| 246 | 252 | the usage of the `AddEnvironmentCleanupHook()` function: | |
@@ -254,13 +260,62 @@ void AddEnvironmentCleanupHook(v8::Isolate* isolate, | |||
| 254 | 260 | This function adds a hook that will run before a given Node.js instance shuts | |
| 255 | 261 | down. If necessary, such hooks can be removed using | |
| 256 | 262 | `RemoveEnvironmentCleanupHook()` before they are run, which has the same | |
| 257 | - signature. | ||
| 263 | + signature. Callbacks are run in last-in first-out order. | ||
| 258 | 264 | ||
| 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`: | ||
| 261 | 266 | ||
| 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 | + ``` | ||
| 264 | 319 | ||
| 265 | 320 | ### Building | |
| 266 | 321 | ||
@@ -1293,85 +1348,6 @@ console.log(result); | |||
| 1293 | 1348 | // Prints: 30 | |
| 1294 | 1349 | ``` | |
| 1295 | 1350 | ||
| 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 | - | ||
| 1375 | 1351 | [`Worker`]: worker_threads.html#worker_threads_class_worker | |
| 1376 | 1352 | [Electron]: https://electronjs.org/ | |
| 1377 | 1353 | [Embedder's Guide]: https://github.com/v8/v8/wiki/Embedder's%20Guide | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -664,16 +664,27 @@ extern "C" NODE_EXTERN void node_module_register(void* mod); | |||
| 664 | 664 | ||
| 665 | 665 | /* Called after the event loop exits but before the VM is disposed. | |
| 666 | 666 | * Callbacks are run in reverse order of registration, i.e. newest first. | |
| 667 | + * | ||
| 668 | + * You should always use the three-argument variant (or, for addons, | ||
| 669 | + * AddEnvironmentCleanupHook) in order to avoid relying on global state. | ||
| 667 | 670 | */ | |
| 668 | - NODE_EXTERN void AtExit(void (*cb)(void* arg), void* arg = nullptr); | ||
| 671 | + NODE_DEPRECATED( | ||
| 672 | + "Use the three-argument variant of AtExit() or AddEnvironmentCleanupHook()", | ||
| 673 | + NODE_EXTERN void AtExit(void (*cb)(void* arg), void* arg = nullptr)); | ||
| 669 | 674 | ||
| 670 | 675 | /* Registers a callback with the passed-in Environment instance. The callback | |
| 671 | 676 | * is called after the event loop exits, but before the VM is disposed. | |
| 672 | 677 | * Callbacks are run in reverse order of registration, i.e. newest first. | |
| 673 | 678 | */ | |
| 674 | 679 | NODE_EXTERN void AtExit(Environment* env, | |
| 675 | 680 | void (*cb)(void* arg), | |
| 676 | - void* arg = nullptr); | ||
| 681 | + void* arg); | ||
| 682 | + NODE_DEPRECATED( | ||
| 683 | + "Use the three-argument variant of AtExit() or AddEnvironmentCleanupHook()", | ||
| 684 | + inline void AtExit(Environment* env, | ||
| 685 | + void (*cb)(void* arg)) { | ||
| 686 | + AtExit(env, cb, nullptr); | ||
| 687 | + }) | ||
| 677 | 688 | ||
| 678 | 689 | typedef double async_id; | |
| 679 | 690 | struct async_context { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,7 +3,11 @@ | |||
| 3 | 3 | #include <node.h> | |
| 4 | 4 | #include <v8.h> | |
| 5 | 5 | ||
| 6 | + // TODO(addaleax): Maybe merge this file with the cctest for AtExit()? | ||
| 7 | + | ||
| 6 | 8 | using node::AtExit; | |
| 9 | + using node::Environment; | ||
| 10 | + using node::GetCurrentEnvironment; | ||
| 7 | 11 | using v8::HandleScope; | |
| 8 | 12 | using v8::Isolate; | |
| 9 | 13 | using v8::Local; | |
@@ -46,9 +50,10 @@ NODE_C_DTOR(sanity_check) { | |||
| 46 | 50 | } | |
| 47 | 51 | ||
| 48 | 52 | void init(Local<Object> exports) { | |
| 49 | - AtExit(at_exit_cb1, exports->GetIsolate()); | ||
| 50 | - AtExit(at_exit_cb2, cookie); | ||
| 51 | - AtExit(at_exit_cb2, cookie); | ||
| 53 | + Environment* env = GetCurrentEnvironment(exports->CreationContext()); | ||
| 54 | + AtExit(env, at_exit_cb1, exports->GetIsolate()); | ||
| 55 | + AtExit(env, at_exit_cb2, cookie); | ||
| 56 | + AtExit(env, at_exit_cb2, cookie); | ||
| 52 | 57 | } | |
| 53 | 58 | ||
| 54 | 59 | NODE_MODULE(NODE_GYP_MODULE_NAME, init) | |
| Back | FazBrowse Home | New Git URL |
0 commit comments