diff options
author | Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> | 2024-08-28 10:33:47 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-28 10:33:47 -0700 |
commit | 7dd861aa36974d5afa9633078b51c4c7f17cf181 (patch) | |
tree | 4cc81fba16d87433ab6d04d377ad0f2590560367 /ext | |
parent | 0e50bb1d4abd80da3fc1be17978760ddfa8560fa (diff) |
fix(napi): Fix worker threads importing already-loaded NAPI addon (#25245)
Part of #20613.
If a node addon is using the legacy `napi_module_register` on ctor
approach to module registration, we have to store the registered module
so that other threads can load the addon (because `napi_module_register`
will only be called once per process).
Diffstat (limited to 'ext')
-rw-r--r-- | ext/napi/lib.rs | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/ext/napi/lib.rs b/ext/napi/lib.rs index faf8a5777..c9dc62a8b 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<HashMap<String, NapiModuleHandle>>, +> = std::sync::LazyLock::new(|| RwLock::new(HashMap::new())); + #[op2(reentrant)] fn op_napi_open<NP, 'scope>( scope: &mut v8::HandleScope<'scope>, @@ -575,11 +586,23 @@ where 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::<napi_register_module_v1>(b"napi_register_module_v1") } { |