Skip to content

Commit

Permalink
test,doc: add tests and docs for addon unloading
Browse files Browse the repository at this point in the history
Originally from portions of #23319.

Backport-PR-URL: #25258
PR-URL: #24861
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
  • Loading branch information
addaleax authored and targos committed Jan 1, 2019
1 parent f2abe7b commit 95353c7
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 0 deletions.
18 changes: 18 additions & 0 deletions doc/api/addons.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,23 @@ NODE_MODULE_INIT(/* exports, module, context */) {
}
```

#### Worker support

In order to support [`Worker`][] threads, addons need to clean up any resources
they may have allocated when such a thread exists. This can be achieved through
the usage of the `AddEnvironmentCleanupHook()` function:

```c++
void AddEnvironmentCleanupHook(v8::Isolate* isolate,
void (*fun)(void* arg),
void* arg);
```
This function adds a hook that will run before a given Node.js instance shuts
down. If necessary, such hooks can be removed using
`RemoveEnvironmentCleanupHook()` before they are run, which has the same
signature.
### Building
Once the source code has been written, it must be compiled into the binary
Expand Down Expand Up @@ -1349,6 +1366,7 @@ Test in JavaScript by running:
require('./build/Release/addon');
```

[`Worker`]: worker_threads.html#worker_threads_class_worker
[Electron]: https://electronjs.org/
[Embedder's Guide]: https://github.com/v8/v8/wiki/Embedder's%20Guide
[Linking to Node.js' own dependencies]: #addons_linking_to_node_js_own_dependencies
Expand Down
14 changes: 14 additions & 0 deletions test/addons/hello-world/test-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Flags: --experimental-worker
'use strict';
const common = require('../../common');
const assert = require('assert');
const path = require('path');
const { Worker } = require('worker_threads');
const binding = path.resolve(__dirname, `./build/${common.buildType}/binding`);

const w = new Worker(`
require('worker_threads').parentPort.postMessage(
require(${JSON.stringify(binding)}).hello());`, { eval: true });
w.on('message', common.mustCall((message) => {
assert.strictEqual(message, 'world');
}));
46 changes: 46 additions & 0 deletions test/addons/worker-addon/binding.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <assert.h>
#include <node.h>
#include <stdio.h>
#include <stdlib.h>
#include <v8.h>

using v8::Context;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Value;

size_t count = 0;

struct statically_allocated {
statically_allocated() {
assert(count == 0);
printf("ctor ");
}
~statically_allocated() {
assert(count == 0);
printf("dtor");
}
} var;

void Dummy(void*) {
assert(0);
}

void Cleanup(void* str) {
printf("%s ", static_cast<const char*>(str));
}

void Initialize(Local<Object> exports,
Local<Value> module,
Local<Context> context) {
node::AddEnvironmentCleanupHook(
context->GetIsolate(),
Cleanup,
const_cast<void*>(static_cast<const void*>("cleanup")));
node::AddEnvironmentCleanupHook(context->GetIsolate(), Dummy, nullptr);
node::RemoveEnvironmentCleanupHook(context->GetIsolate(), Dummy, nullptr);
}

NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize)
9 changes: 9 additions & 0 deletions test/addons/worker-addon/binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
'targets': [
{
'target_name': 'binding',
'defines': [ 'V8_DEPRECATION_WARNINGS=1' ],
'sources': [ 'binding.cc' ]
}
]
}
21 changes: 21 additions & 0 deletions test/addons/worker-addon/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Flags: --experimental-worker
'use strict';
const common = require('../../common');
const assert = require('assert');
const child_process = require('child_process');
const path = require('path');
const { Worker } = require('worker_threads');
const binding = path.resolve(__dirname, `./build/${common.buildType}/binding`);

if (process.argv[2] === 'child') {
new Worker(`require(${JSON.stringify(binding)});`, { eval: true });
} else {
const proc = child_process.spawnSync(process.execPath, [
'--experimental-worker',
__filename,
'child'
]);
assert.strictEqual(proc.stderr.toString(), '');
assert.strictEqual(proc.stdout.toString(), 'ctor cleanup dtor');
assert.strictEqual(proc.status, 0);
}

0 comments on commit 95353c7

Please sign in to comment.