Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
test,doc: add tests and docs for addon unloading
Originally from portions of #23319.

PR-URL: #24861
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
  • Loading branch information
addaleax authored and Gabriel Schulhof committed Dec 28, 2018
commit 1c2b202227d0ccf34455f075fdcfb9f31c424f3b
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);
}