Skip to content

Commit 95353c7

Browse files
addaleaxtargos
authored andcommitted
test,doc: add tests and docs for addon unloading
Originally from portions of #23319. Backport-PR-URL: #25258 PR-URL: #24861 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent f2abe7b commit 95353c7

File tree

5 files changed

+108
-0
lines changed

5 files changed

+108
-0
lines changed

doc/api/addons.md

+18
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,23 @@ NODE_MODULE_INIT(/* exports, module, context */) {
234234
}
235235
```
236236

237+
#### Worker support
238+
239+
In order to support [`Worker`][] threads, addons need to clean up any resources
240+
they may have allocated when such a thread exists. This can be achieved through
241+
the usage of the `AddEnvironmentCleanupHook()` function:
242+
243+
```c++
244+
void AddEnvironmentCleanupHook(v8::Isolate* isolate,
245+
void (*fun)(void* arg),
246+
void* arg);
247+
```
248+
249+
This function adds a hook that will run before a given Node.js instance shuts
250+
down. If necessary, such hooks can be removed using
251+
`RemoveEnvironmentCleanupHook()` before they are run, which has the same
252+
signature.
253+
237254
### Building
238255
239256
Once the source code has been written, it must be compiled into the binary
@@ -1349,6 +1366,7 @@ Test in JavaScript by running:
13491366
require('./build/Release/addon');
13501367
```
13511368

1369+
[`Worker`]: worker_threads.html#worker_threads_class_worker
13521370
[Electron]: https://electronjs.org/
13531371
[Embedder's Guide]: https://github.com/v8/v8/wiki/Embedder's%20Guide
13541372
[Linking to Node.js' own dependencies]: #addons_linking_to_node_js_own_dependencies
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Flags: --experimental-worker
2+
'use strict';
3+
const common = require('../../common');
4+
const assert = require('assert');
5+
const path = require('path');
6+
const { Worker } = require('worker_threads');
7+
const binding = path.resolve(__dirname, `./build/${common.buildType}/binding`);
8+
9+
const w = new Worker(`
10+
require('worker_threads').parentPort.postMessage(
11+
require(${JSON.stringify(binding)}).hello());`, { eval: true });
12+
w.on('message', common.mustCall((message) => {
13+
assert.strictEqual(message, 'world');
14+
}));

test/addons/worker-addon/binding.cc

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <assert.h>
2+
#include <node.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <v8.h>
6+
7+
using v8::Context;
8+
using v8::HandleScope;
9+
using v8::Isolate;
10+
using v8::Local;
11+
using v8::Object;
12+
using v8::Value;
13+
14+
size_t count = 0;
15+
16+
struct statically_allocated {
17+
statically_allocated() {
18+
assert(count == 0);
19+
printf("ctor ");
20+
}
21+
~statically_allocated() {
22+
assert(count == 0);
23+
printf("dtor");
24+
}
25+
} var;
26+
27+
void Dummy(void*) {
28+
assert(0);
29+
}
30+
31+
void Cleanup(void* str) {
32+
printf("%s ", static_cast<const char*>(str));
33+
}
34+
35+
void Initialize(Local<Object> exports,
36+
Local<Value> module,
37+
Local<Context> context) {
38+
node::AddEnvironmentCleanupHook(
39+
context->GetIsolate(),
40+
Cleanup,
41+
const_cast<void*>(static_cast<const void*>("cleanup")));
42+
node::AddEnvironmentCleanupHook(context->GetIsolate(), Dummy, nullptr);
43+
node::RemoveEnvironmentCleanupHook(context->GetIsolate(), Dummy, nullptr);
44+
}
45+
46+
NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize)

test/addons/worker-addon/binding.gyp

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding',
5+
'defines': [ 'V8_DEPRECATION_WARNINGS=1' ],
6+
'sources': [ 'binding.cc' ]
7+
}
8+
]
9+
}

test/addons/worker-addon/test.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Flags: --experimental-worker
2+
'use strict';
3+
const common = require('../../common');
4+
const assert = require('assert');
5+
const child_process = require('child_process');
6+
const path = require('path');
7+
const { Worker } = require('worker_threads');
8+
const binding = path.resolve(__dirname, `./build/${common.buildType}/binding`);
9+
10+
if (process.argv[2] === 'child') {
11+
new Worker(`require(${JSON.stringify(binding)});`, { eval: true });
12+
} else {
13+
const proc = child_process.spawnSync(process.execPath, [
14+
'--experimental-worker',
15+
__filename,
16+
'child'
17+
]);
18+
assert.strictEqual(proc.stderr.toString(), '');
19+
assert.strictEqual(proc.stdout.toString(), 'ctor cleanup dtor');
20+
assert.strictEqual(proc.status, 0);
21+
}

0 commit comments

Comments
 (0)