diff --git a/src/node.cc b/src/node.cc index 71af5b93f6632e..33ffba6924c464 100644 --- a/src/node.cc +++ b/src/node.cc @@ -183,7 +183,9 @@ static int v8_thread_pool_size = v8_default_thread_pool_size; static bool prof_process = false; static bool v8_is_profiling = false; static bool node_is_initialized = false; +static Mutex module_mutex; static node_module* modpending; +static std::unordered_map modmap_metadata; static node_module* modlist_builtin; static node_module* modlist_internal; static node_module* modlist_linked; @@ -1266,8 +1268,6 @@ static void DLOpen(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); auto context = env->context(); - CHECK_NULL(modpending); - if (args.Length() < 2) { env->ThrowError("process.dlopen needs at least 2 arguments."); return; @@ -1289,13 +1289,27 @@ static void DLOpen(const FunctionCallbackInfo& args) { node::Utf8Value filename(env->isolate(), args[1]); // Cast DLib dlib(*filename, flags); - bool is_opened = dlib.Open(); - - // Objects containing v14 or later modules will have registered themselves - // on the pending list. Activate all of them now. At present, only one - // module per object is supported. - node_module* const mp = modpending; - modpending = nullptr; + bool is_opened; + node_module* mp; + { + Mutex::ScopedLock lock(module_mutex); + CHECK_NULL(modpending); + is_opened = dlib.Open(); + // Objects containing v14 or later modules will have registered themselves + // on the pending list. Activate all of them now. At present, only one + // module per object is supported. + std::string key(*filename, filename.length()); + mp = modpending; + if (mp) { + modpending = nullptr; + modmap_metadata.emplace(std::move(key), mp); + } else { + auto existing = modmap_metadata.find(key); + if (existing != modmap_metadata.end()) { + mp = existing->second; + } + } + } if (!is_opened) { Local errmsg = OneByteString(env->isolate(), dlib.errmsg_.c_str()); diff --git a/test/addons/hello-world-from-worker/binding.cc b/test/addons/hello-world-from-worker/binding.cc new file mode 100644 index 00000000000000..55d64b3d6c3513 --- /dev/null +++ b/test/addons/hello-world-from-worker/binding.cc @@ -0,0 +1,13 @@ +#include +#include + +void Method(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = args.GetIsolate(); + args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); +} + +void init(v8::Local exports, v8::Local module) { + NODE_SET_METHOD(module, "exports", Method); +} + +NODE_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/test/addons/hello-world-from-worker/binding.gyp b/test/addons/hello-world-from-worker/binding.gyp new file mode 100644 index 00000000000000..7ede63d94a0d77 --- /dev/null +++ b/test/addons/hello-world-from-worker/binding.gyp @@ -0,0 +1,9 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], + 'sources': [ 'binding.cc' ] + } + ] +} diff --git a/test/addons/hello-world-from-worker/test.js b/test/addons/hello-world-from-worker/test.js new file mode 100644 index 00000000000000..ff96a16ca012f8 --- /dev/null +++ b/test/addons/hello-world-from-worker/test.js @@ -0,0 +1,32 @@ +// Flags: --experimental-worker +'use strict'; +const assert = require('assert'); + +function testModule() { + const common = require('../../common'); + const binding = require(`./build/${common.buildType}/binding`); + assert.strictEqual(binding(), 'world'); + console.log('binding.hello() =', binding()); +} + +const { Worker, isMainThread, parentPort } = require('worker_threads'); +if (isMainThread) { + testModule(); + const worker = new Worker(__filename); + worker.on('message', (message) => { + assert.strictEqual(message, undefined); + worker.terminate(); + }); + worker.on('error', (error) => { + console.error(error); + worker.terminate(); + }); +} else { + let response; + try { + testModule(); + } catch (e) { + response = e + ''; + } + parentPort.postMessage(response); +}