From 78159c38fea74e398e359fa631d3ac2f99ce6325 Mon Sep 17 00:00:00 2001 From: Ryan Petrich Date: Sun, 24 Jun 2018 22:49:47 -0400 Subject: [PATCH] src: permit native modules to be loaded in more than one context Maintain metadata on loaded native modules so that if additional contexts load the same module, the metadata will be reused and the registration function dispatched again. Fix race condition where if multiple contexts load modules at the same time, it's possible one of them could fail to load. --- src/node.cc | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) 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());