From 4e4bcdd19e9733d35c7b00227a8041b756fe110b Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 27 Aug 2024 17:57:00 -0700 Subject: [PATCH 1/3] Store loaded module handle in napi --- ext/napi/lib.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ext/napi/lib.rs b/ext/napi/lib.rs index faf8a577776fbe..6210229ed6ffd3 100644 --- a/ext/napi/lib.rs +++ b/ext/napi/lib.rs @@ -9,11 +9,13 @@ use core::ptr::NonNull; use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::op2; +use deno_core::parking_lot::RwLock; use deno_core::url::Url; use deno_core::ExternalOpsTracker; use deno_core::OpState; use deno_core::V8CrossThreadTaskSpawner; use std::cell::RefCell; +use std::collections::HashMap; use std::path::Path; use std::path::PathBuf; use std::rc::Rc; @@ -493,6 +495,15 @@ impl NapiPermissions for deno_permissions::PermissionsContainer { } } +unsafe impl Sync for NapiModuleHandle {} +unsafe impl Send for NapiModuleHandle {} +#[derive(Clone, Copy)] +struct NapiModuleHandle(*const NapiModule); + +static NAPI_LOADED_MODULES: std::sync::LazyLock< + RwLock>, +> = std::sync::LazyLock::new(|| RwLock::new(HashMap::new())); + #[op2(reentrant)] fn op_napi_open( scope: &mut v8::HandleScope<'scope>, @@ -573,13 +584,25 @@ where // The `module.exports` object. let exports = v8::Object::new(scope); - + let maybe_exports = if let Some(module_to_register) = maybe_module { + NAPI_LOADED_MODULES + .write() + .insert(path, NapiModuleHandle(module_to_register)); // SAFETY: napi_register_module guarantees that `module_to_register` is valid. let nm = unsafe { &*module_to_register }; assert_eq!(nm.nm_version, 1); // SAFETY: we are going blind, calling the register function on the other side. unsafe { (nm.nm_register_func)(env_ptr, exports.into()) } + } else if let Some(module_to_register) = + { NAPI_LOADED_MODULES.read().get(&path).copied() } + { + // SAFETY: this originated from `napi_register_module`, so the + // pointer should still be valid. + let nm = unsafe { &*module_to_register.0 }; + assert_eq!(nm.nm_version, 1); + // SAFETY: we are going blind, calling the register function on the other side. + unsafe { (nm.nm_register_func)(env_ptr, exports.into()) } } else if let Ok(init) = unsafe { library.get::(b"napi_register_module_v1") } { From d61bb2758964b90ce721f8caef01ff35d8b0a950 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 27 Aug 2024 17:57:25 -0700 Subject: [PATCH 2/3] Add test --- tests/napi/init_test.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/napi/init_test.js b/tests/napi/init_test.js index 9db99d8a050146..9486824780de3b 100644 --- a/tests/napi/init_test.js +++ b/tests/napi/init_test.js @@ -2,6 +2,7 @@ import { Buffer } from "node:buffer"; import { assert, libSuffix } from "./common.js"; +import { Worker } from "node:worker_threads"; const ops = Deno[Deno.internal].core.ops; @@ -13,3 +14,37 @@ Deno.test("ctr initialization (napi_module_register)", { assert(obj != null); assert(typeof obj === "object"); }); + +Deno.test("ctr initialization by multiple threads (napi_module_register)", { + ignore: Deno.build.os == "windows", +}, async function () { + const path = new URL(`./module.${libSuffix}`, import.meta.url).pathname; + const obj = ops.op_napi_open(path, {}, Buffer, reportError); + const common = import.meta.resolve("./common.js"); + assert(obj != null); + assert(typeof obj === "object"); + + const worker = new Worker( + ` + import { Buffer } from "node:buffer"; + import { parentPort } from "node:worker_threads"; + import { assert } from "${common}"; + + const ops = Deno[Deno.internal].core.ops; + const obj = ops.op_napi_open("${path}", {}, Buffer, reportError); + assert(obj != null); + assert(typeof obj === "object"); + parentPort.postMessage("ok"); + `, + { + eval: true, + }, + ); + + const p = Promise.withResolvers(); + worker.on("message", (_m) => { + p.resolve(); + }); + + await p.promise; +}); From 7cffcbe50fe6e90cb52b8f96b7a680c4fd5da17c Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 27 Aug 2024 17:58:31 -0700 Subject: [PATCH 3/3] Fmt --- ext/napi/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/napi/lib.rs b/ext/napi/lib.rs index 6210229ed6ffd3..c9dc62a8b37cc9 100644 --- a/ext/napi/lib.rs +++ b/ext/napi/lib.rs @@ -584,7 +584,7 @@ where // The `module.exports` object. let exports = v8::Object::new(scope); - + let maybe_exports = if let Some(module_to_register) = maybe_module { NAPI_LOADED_MODULES .write()