Skip to content

Commit

Permalink
src: fix race on modpending
Browse files Browse the repository at this point in the history
Fixes a rare race condition on modpending when two native modules are
loaded simultaneously on different threads by storing it thread-
locally.

PR-URL: #21611
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
  • Loading branch information
rpetrich authored and targos committed Sep 3, 2018
1 parent c894145 commit 866965e
Showing 1 changed file with 12 additions and 5 deletions.
17 changes: 12 additions & 5 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ 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 node_module* modpending;
static uv_once_t init_modpending_once = UV_ONCE_INIT;
static uv_key_t thread_local_modpending;
static node_module* modlist_builtin;
static node_module* modlist_internal;
static node_module* modlist_linked;
Expand Down Expand Up @@ -1254,7 +1255,7 @@ extern "C" void node_module_register(void* m) {
mp->nm_link = modlist_linked;
modlist_linked = mp;
} else {
modpending = mp;
uv_key_set(&thread_local_modpending, mp);
}
}

Expand Down Expand Up @@ -1368,6 +1369,10 @@ inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
reinterpret_cast<napi_addon_register_func>(dlib->GetSymbolAddress(name));
}

void InitModpendingOnce() {
CHECK_EQ(0, uv_key_create(&thread_local_modpending));
}

// DLOpen is process.dlopen(module, filename, flags).
// Used to load 'module.node' dynamically shared objects.
//
Expand All @@ -1378,7 +1383,8 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
auto context = env->context();

CHECK_NULL(modpending);
uv_once(&init_modpending_once, InitModpendingOnce);
CHECK_NULL(uv_key_get(&thread_local_modpending));

if (args.Length() < 2) {
env->ThrowError("process.dlopen needs at least 2 arguments.");
Expand Down Expand Up @@ -1406,8 +1412,9 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) {
// 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;
node_module* const mp = static_cast<node_module*>(
uv_key_get(&thread_local_modpending));
uv_key_set(&thread_local_modpending, nullptr);

if (!is_opened) {
Local<String> errmsg = OneByteString(env->isolate(), dlib.errmsg_.c_str());
Expand Down

0 comments on commit 866965e

Please sign in to comment.