fix(napi): drop all thread_local! usage
This commit is contained in:
parent
7203632bb3
commit
788a962137
13 changed files with 82 additions and 127 deletions
|
@ -49,7 +49,8 @@ impl TryToTokens for NapiFn {
|
||||||
quote! {
|
quote! {
|
||||||
// constructor function is called from class `factory`
|
// constructor function is called from class `factory`
|
||||||
// so we should skip the original `constructor` logic
|
// so we should skip the original `constructor` logic
|
||||||
if napi::bindgen_prelude::___CALL_FROM_FACTORY.with(|inner| inner.load(std::sync::atomic::Ordering::Relaxed)) {
|
let inner = napi::__private::___CALL_FROM_FACTORY.get_or_default();
|
||||||
|
if inner.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
return std::ptr::null_mut();
|
return std::ptr::null_mut();
|
||||||
}
|
}
|
||||||
napi::bindgen_prelude::CallbackInfo::<#args_len>::new(env, cb, None).and_then(|mut cb| {
|
napi::bindgen_prelude::CallbackInfo::<#args_len>::new(env, cb, None).and_then(|mut cb| {
|
||||||
|
|
|
@ -276,12 +276,14 @@ impl NapiStruct {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut result = std::ptr::null_mut();
|
let mut result = std::ptr::null_mut();
|
||||||
napi::bindgen_prelude::___CALL_FROM_FACTORY.with(|inner| inner.store(true, std::sync::atomic::Ordering::Relaxed));
|
let inner = napi::__private::___CALL_FROM_FACTORY.get_or_default();
|
||||||
|
inner.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
napi::check_status!(
|
napi::check_status!(
|
||||||
napi::sys::napi_new_instance(env, ctor, 0, std::ptr::null_mut(), &mut result),
|
napi::sys::napi_new_instance(env, ctor, 0, std::ptr::null_mut(), &mut result),
|
||||||
"Failed to construct class `{}`",
|
"Failed to construct class `{}`",
|
||||||
#js_name_raw
|
#js_name_raw
|
||||||
)?;
|
)?;
|
||||||
|
inner.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||||
let mut object_ref = std::ptr::null_mut();
|
let mut object_ref = std::ptr::null_mut();
|
||||||
let initial_finalize: Box<dyn FnOnce()> = Box::new(|| {});
|
let initial_finalize: Box<dyn FnOnce()> = Box::new(|| {});
|
||||||
let finalize_callbacks_ptr = std::rc::Rc::into_raw(std::rc::Rc::new(std::cell::Cell::new(Box::into_raw(initial_finalize))));
|
let finalize_callbacks_ptr = std::rc::Rc::into_raw(std::rc::Rc::new(std::cell::Cell::new(Box::into_raw(initial_finalize))));
|
||||||
|
@ -298,7 +300,6 @@ impl NapiStruct {
|
||||||
#js_name_raw
|
#js_name_raw
|
||||||
)?;
|
)?;
|
||||||
napi::bindgen_prelude::Reference::<#name>::add_ref(wrapped_value, (wrapped_value, object_ref, finalize_callbacks_ptr));
|
napi::bindgen_prelude::Reference::<#name>::add_ref(wrapped_value, (wrapped_value, object_ref, finalize_callbacks_ptr));
|
||||||
napi::bindgen_prelude::___CALL_FROM_FACTORY.with(|inner| inner.store(false, std::sync::atomic::Ordering::Relaxed));
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,6 +317,7 @@ impl NapiStruct {
|
||||||
|
|
||||||
fn gen_to_napi_value_ctor_impl(&self) -> TokenStream {
|
fn gen_to_napi_value_ctor_impl(&self) -> TokenStream {
|
||||||
let name = &self.name;
|
let name = &self.name;
|
||||||
|
let js_name_without_null = &self.js_name;
|
||||||
let js_name_str = format!("{}\0", &self.js_name);
|
let js_name_str = format!("{}\0", &self.js_name);
|
||||||
|
|
||||||
let mut field_conversions = vec![];
|
let mut field_conversions = vec![];
|
||||||
|
@ -362,7 +364,7 @@ impl NapiStruct {
|
||||||
napi::bindgen_prelude::check_status!(
|
napi::bindgen_prelude::check_status!(
|
||||||
napi::bindgen_prelude::sys::napi_get_reference_value(env, ctor_ref, &mut ctor),
|
napi::bindgen_prelude::sys::napi_get_reference_value(env, ctor_ref, &mut ctor),
|
||||||
"Failed to get constructor reference of class `{}`",
|
"Failed to get constructor reference of class `{}`",
|
||||||
#js_name_str
|
#js_name_without_null
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut instance_value = std::ptr::null_mut();
|
let mut instance_value = std::ptr::null_mut();
|
||||||
|
@ -372,7 +374,7 @@ impl NapiStruct {
|
||||||
napi::bindgen_prelude::check_status!(
|
napi::bindgen_prelude::check_status!(
|
||||||
napi::bindgen_prelude::sys::napi_new_instance(env, ctor, args.len(), args.as_ptr(), &mut instance_value),
|
napi::bindgen_prelude::sys::napi_new_instance(env, ctor, args.len(), args.as_ptr(), &mut instance_value),
|
||||||
"Failed to construct class `{}`",
|
"Failed to construct class `{}`",
|
||||||
#js_name_str
|
#js_name_without_null
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(instance_value)
|
Ok(instance_value)
|
||||||
|
|
|
@ -2,8 +2,7 @@ mod macos;
|
||||||
|
|
||||||
pub fn setup() {
|
pub fn setup() {
|
||||||
println!("cargo:rerun-if-env-changed=DEBUG_GENERATED_CODE");
|
println!("cargo:rerun-if-env-changed=DEBUG_GENERATED_CODE");
|
||||||
match std::env::var("CARGO_CFG_TARGET_OS").as_deref() {
|
if let Ok("macos") = std::env::var("CARGO_CFG_TARGET_OS").as_deref() {
|
||||||
Ok("macos") => macos::setup(),
|
macos::setup();
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ tokio_time = ["tokio/time"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ctor = "0.1"
|
ctor = "0.1"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
|
thread_local = "1"
|
||||||
|
|
||||||
[dependencies.napi-sys]
|
[dependencies.napi-sys]
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
|
|
|
@ -4,12 +4,15 @@ use std::ptr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use thread_local::ThreadLocal;
|
||||||
|
|
||||||
use crate::{bindgen_prelude::*, check_status, sys, Result};
|
use crate::{bindgen_prelude::*, check_status, sys, Result};
|
||||||
|
|
||||||
thread_local! {
|
lazy_static! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// Determined is `constructor` called from Class `factory`
|
/// Determined is `constructor` called from Class `factory`
|
||||||
pub static ___CALL_FROM_FACTORY: AtomicBool = AtomicBool::new(false);
|
pub static ref ___CALL_FROM_FACTORY: ThreadLocal<AtomicBool> = ThreadLocal::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CallbackInfo<const N: usize> {
|
pub struct CallbackInfo<const N: usize> {
|
||||||
|
@ -113,9 +116,10 @@ impl<const N: usize> CallbackInfo<N> {
|
||||||
let this = self.this();
|
let this = self.this();
|
||||||
let mut instance = ptr::null_mut();
|
let mut instance = ptr::null_mut();
|
||||||
unsafe {
|
unsafe {
|
||||||
___CALL_FROM_FACTORY.with(|inner| inner.store(true, Ordering::Relaxed));
|
let inner = ___CALL_FROM_FACTORY.get_or_default();
|
||||||
|
inner.store(true, Ordering::Relaxed);
|
||||||
let status = sys::napi_new_instance(self.env, this, 0, ptr::null_mut(), &mut instance);
|
let status = sys::napi_new_instance(self.env, this, 0, ptr::null_mut(), &mut instance);
|
||||||
___CALL_FROM_FACTORY.with(|inner| inner.store(false, Ordering::Relaxed));
|
inner.store(false, Ordering::Relaxed);
|
||||||
// Error thrown in `constructor`
|
// Error thrown in `constructor`
|
||||||
if status == sys::Status::napi_pending_exception {
|
if status == sys::Status::napi_pending_exception {
|
||||||
let mut exception = ptr::null_mut();
|
let mut exception = ptr::null_mut();
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::{check_status, sys, JsGlobal, JsNull, JsUndefined, NapiValue, Result};
|
use crate::{check_status, sys, JsGlobal, JsNull, JsUndefined, NapiValue, Result};
|
||||||
|
@ -7,11 +6,6 @@ use super::Array;
|
||||||
|
|
||||||
pub use crate::Env;
|
pub use crate::Env;
|
||||||
|
|
||||||
thread_local! {
|
|
||||||
static JS_UNDEFINED: RefCell<Option<JsUndefined>> = RefCell::default();
|
|
||||||
static JS_NULL: RefCell<Option<JsNull>> = RefCell::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Env {
|
impl Env {
|
||||||
pub fn create_array(&self, len: u32) -> Result<Array> {
|
pub fn create_array(&self, len: u32) -> Result<Array> {
|
||||||
Array::new(self.0, len)
|
Array::new(self.0, len)
|
||||||
|
@ -19,26 +13,16 @@ impl Env {
|
||||||
|
|
||||||
/// Get [JsUndefined](./struct.JsUndefined.html) value
|
/// Get [JsUndefined](./struct.JsUndefined.html) value
|
||||||
pub fn get_undefined(&self) -> Result<JsUndefined> {
|
pub fn get_undefined(&self) -> Result<JsUndefined> {
|
||||||
if let Some(js_undefined) = JS_UNDEFINED.with(|x| *x.borrow()) {
|
|
||||||
return Ok(js_undefined);
|
|
||||||
}
|
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
check_status!(unsafe { sys::napi_get_undefined(self.0, &mut raw_value) })?;
|
check_status!(unsafe { sys::napi_get_undefined(self.0, &mut raw_value) })?;
|
||||||
let js_undefined = unsafe { JsUndefined::from_raw_unchecked(self.0, raw_value) };
|
let js_undefined = unsafe { JsUndefined::from_raw_unchecked(self.0, raw_value) };
|
||||||
JS_UNDEFINED.with(|x| x.borrow_mut().replace(js_undefined));
|
|
||||||
Ok(js_undefined)
|
Ok(js_undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_null(&self) -> Result<JsNull> {
|
pub fn get_null(&self) -> Result<JsNull> {
|
||||||
if let Some(js_null) = JS_NULL.with(|cell| *cell.borrow()) {
|
|
||||||
return Ok(js_null);
|
|
||||||
}
|
|
||||||
let mut raw_value = ptr::null_mut();
|
let mut raw_value = ptr::null_mut();
|
||||||
check_status!(unsafe { sys::napi_get_null(self.0, &mut raw_value) })?;
|
check_status!(unsafe { sys::napi_get_null(self.0, &mut raw_value) })?;
|
||||||
let js_null = unsafe { JsNull::from_raw_unchecked(self.0, raw_value) };
|
let js_null = unsafe { JsNull::from_raw_unchecked(self.0, raw_value) };
|
||||||
JS_NULL.with(|js_null_cell| {
|
|
||||||
js_null_cell.borrow_mut().replace(js_null);
|
|
||||||
});
|
|
||||||
Ok(js_null)
|
Ok(js_null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::Cell;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{bindgen_runtime::ToNapiValue, check_status, Env, Error, Result, Status};
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bindgen_runtime::{PersistedSingleThreadHashMap, ToNapiValue},
|
||||||
|
check_status, Env, Error, Result, Status,
|
||||||
|
};
|
||||||
|
|
||||||
type RefInformation = (
|
type RefInformation = (
|
||||||
*mut c_void,
|
*mut c_void,
|
||||||
|
@ -12,8 +16,9 @@ type RefInformation = (
|
||||||
*const Cell<*mut dyn FnOnce()>,
|
*const Cell<*mut dyn FnOnce()>,
|
||||||
);
|
);
|
||||||
|
|
||||||
thread_local! {
|
lazy_static! {
|
||||||
pub(crate) static REFERENCE_MAP: RefCell<HashMap<*mut c_void, RefInformation>> = Default::default();
|
pub(crate) static ref REFERENCE_MAP: PersistedSingleThreadHashMap<*mut c_void, RefInformation> =
|
||||||
|
Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### Experimental feature
|
/// ### Experimental feature
|
||||||
|
@ -57,15 +62,15 @@ impl<T> Drop for Reference<T> {
|
||||||
impl<T: 'static> Reference<T> {
|
impl<T: 'static> Reference<T> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn add_ref(t: *mut c_void, value: RefInformation) {
|
pub fn add_ref(t: *mut c_void, value: RefInformation) {
|
||||||
REFERENCE_MAP.with(|map| {
|
REFERENCE_MAP.borrow_mut(|map| {
|
||||||
map.borrow_mut().insert(t, value);
|
map.insert(t, value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub unsafe fn from_value_ptr(t: *mut c_void, env: crate::sys::napi_env) -> Result<Self> {
|
pub unsafe fn from_value_ptr(t: *mut c_void, env: crate::sys::napi_env) -> Result<Self> {
|
||||||
if let Some((wrapped_value, napi_ref, finalize_callbacks_ptr)) =
|
if let Some((wrapped_value, napi_ref, finalize_callbacks_ptr)) =
|
||||||
REFERENCE_MAP.with(|map| map.borrow().get(&t).cloned())
|
REFERENCE_MAP.borrow_mut(|map| map.get(&t).cloned())
|
||||||
{
|
{
|
||||||
check_status!(
|
check_status!(
|
||||||
unsafe { crate::sys::napi_reference_ref(env, napi_ref, &mut 0) },
|
unsafe { crate::sys::napi_reference_ref(env, napi_ref, &mut 0) },
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub unsafe extern "C" fn raw_finalize_unchecked<T>(
|
||||||
) {
|
) {
|
||||||
unsafe { Box::from_raw(finalize_data as *mut T) };
|
unsafe { Box::from_raw(finalize_data as *mut T) };
|
||||||
if let Some((_, ref_val, finalize_callbacks_ptr)) =
|
if let Some((_, ref_val, finalize_callbacks_ptr)) =
|
||||||
REFERENCE_MAP.with(|reference_map| reference_map.borrow_mut().remove(&finalize_data))
|
REFERENCE_MAP.borrow_mut(|reference_map| reference_map.remove(&finalize_data))
|
||||||
{
|
{
|
||||||
let finalize_callbacks_rc = unsafe { Rc::from_raw(finalize_callbacks_ptr) };
|
let finalize_callbacks_rc = unsafe { Rc::from_raw(finalize_callbacks_ptr) };
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::{AtomicBool, AtomicPtr};
|
||||||
use std::sync::{atomic::Ordering, Mutex};
|
use std::sync::{atomic::Ordering, Mutex};
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
@ -56,11 +55,11 @@ impl<T> PersistedSingleThreadVec<T> {
|
||||||
unsafe impl<T> Send for PersistedSingleThreadVec<T> {}
|
unsafe impl<T> Send for PersistedSingleThreadVec<T> {}
|
||||||
unsafe impl<T> Sync for PersistedSingleThreadVec<T> {}
|
unsafe impl<T> Sync for PersistedSingleThreadVec<T> {}
|
||||||
|
|
||||||
struct PersistedSingleThreadHashMap<K, V>(Mutex<HashMap<K, V>>);
|
pub(crate) struct PersistedSingleThreadHashMap<K, V>(Mutex<HashMap<K, V>>);
|
||||||
|
|
||||||
impl<K, V> PersistedSingleThreadHashMap<K, V> {
|
impl<K, V> PersistedSingleThreadHashMap<K, V> {
|
||||||
#[allow(clippy::mut_from_ref)]
|
#[allow(clippy::mut_from_ref)]
|
||||||
fn borrow_mut<F, R>(&self, f: F) -> R
|
pub(crate) fn borrow_mut<F, R>(&self, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut HashMap<K, V>) -> R,
|
F: FnOnce(&mut HashMap<K, V>) -> R,
|
||||||
{
|
{
|
||||||
|
@ -89,11 +88,17 @@ type ModuleClassProperty = PersistedSingleThreadHashMap<
|
||||||
unsafe impl<K, V> Send for PersistedSingleThreadHashMap<K, V> {}
|
unsafe impl<K, V> Send for PersistedSingleThreadHashMap<K, V> {}
|
||||||
unsafe impl<K, V> Sync for PersistedSingleThreadHashMap<K, V> {}
|
unsafe impl<K, V> Sync for PersistedSingleThreadHashMap<K, V> {}
|
||||||
|
|
||||||
|
type FnRegisterMap =
|
||||||
|
PersistedSingleThreadHashMap<ExportRegisterCallback, (sys::napi_callback, &'static str)>;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref MODULE_REGISTER_CALLBACK: ModuleRegisterCallback = Default::default();
|
static ref MODULE_REGISTER_CALLBACK: ModuleRegisterCallback = Default::default();
|
||||||
static ref MODULE_CLASS_PROPERTIES: ModuleClassProperty = Default::default();
|
static ref MODULE_CLASS_PROPERTIES: ModuleClassProperty = Default::default();
|
||||||
static ref MODULE_REGISTER_LOCK: Mutex<()> = Mutex::new(());
|
static ref MODULE_REGISTER_LOCK: Mutex<()> = Mutex::new(());
|
||||||
static ref REGISTERED: AtomicBool = AtomicBool::new(false);
|
static ref REGISTERED: AtomicBool = AtomicBool::new(false);
|
||||||
|
static ref REGISTERED_CLASSES: thread_local::ThreadLocal<AtomicPtr<RegisteredClasses>> =
|
||||||
|
thread_local::ThreadLocal::new();
|
||||||
|
static ref FN_REGISTER_MAP: FnRegisterMap = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -103,27 +108,22 @@ fn wait_first_thread_registered() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RegisteredClasses =
|
||||||
|
HashMap</* export name */ String, /* constructor */ sys::napi_ref>;
|
||||||
|
|
||||||
#[cfg(feature = "compat-mode")]
|
#[cfg(feature = "compat-mode")]
|
||||||
// compatibility for #[module_exports]
|
// compatibility for #[module_exports]
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref MODULE_EXPORTS: PersistedSingleThreadVec<ModuleExportsCallback> = Default::default();
|
static ref MODULE_EXPORTS: PersistedSingleThreadVec<ModuleExportsCallback> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
|
||||||
static REGISTERED_CLASSES: RefCell<HashMap<
|
|
||||||
/* export name */ String,
|
|
||||||
/* constructor */ sys::napi_ref,
|
|
||||||
>> = Default::default();
|
|
||||||
static FN_REGISTER_MAP: RefCell<HashMap<ExportRegisterCallback, (sys::napi_callback, String)>> = Default::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn get_class_constructor(js_name: &'static str) -> Option<sys::napi_ref> {
|
pub fn get_class_constructor(js_name: &'static str) -> Option<sys::napi_ref> {
|
||||||
wait_first_thread_registered();
|
wait_first_thread_registered();
|
||||||
REGISTERED_CLASSES.with(|registered_classes| {
|
let registered_classes = REGISTERED_CLASSES.get().unwrap();
|
||||||
let classes = registered_classes.borrow();
|
let registered_classes =
|
||||||
classes.get(js_name).copied()
|
Box::leak(unsafe { Box::from_raw(registered_classes.load(Ordering::Relaxed)) });
|
||||||
})
|
registered_classes.get(js_name).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -148,8 +148,8 @@ pub fn register_js_function(
|
||||||
cb: ExportRegisterCallback,
|
cb: ExportRegisterCallback,
|
||||||
c_fn: sys::napi_callback,
|
c_fn: sys::napi_callback,
|
||||||
) {
|
) {
|
||||||
FN_REGISTER_MAP.with(|inner| {
|
FN_REGISTER_MAP.borrow_mut(|inner| {
|
||||||
inner.borrow_mut().insert(cb, (c_fn, name.to_owned()));
|
inner.insert(cb, (c_fn, name));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,9 +188,8 @@ pub fn register_class(
|
||||||
///
|
///
|
||||||
pub fn get_js_function(env: &Env, raw_fn: ExportRegisterCallback) -> Result<JsFunction> {
|
pub fn get_js_function(env: &Env, raw_fn: ExportRegisterCallback) -> Result<JsFunction> {
|
||||||
wait_first_thread_registered();
|
wait_first_thread_registered();
|
||||||
FN_REGISTER_MAP.with(|inner| {
|
FN_REGISTER_MAP.borrow_mut(|inner| {
|
||||||
inner
|
inner
|
||||||
.borrow()
|
|
||||||
.get(&raw_fn)
|
.get(&raw_fn)
|
||||||
.and_then(|(cb, name)| {
|
.and_then(|(cb, name)| {
|
||||||
let mut function = ptr::null_mut();
|
let mut function = ptr::null_mut();
|
||||||
|
@ -243,9 +242,8 @@ pub fn get_js_function(env: &Env, raw_fn: ExportRegisterCallback) -> Result<JsFu
|
||||||
///
|
///
|
||||||
pub fn get_c_callback(raw_fn: ExportRegisterCallback) -> Result<crate::Callback> {
|
pub fn get_c_callback(raw_fn: ExportRegisterCallback) -> Result<crate::Callback> {
|
||||||
wait_first_thread_registered();
|
wait_first_thread_registered();
|
||||||
FN_REGISTER_MAP.with(|inner| {
|
FN_REGISTER_MAP.borrow_mut(|inner| {
|
||||||
inner
|
inner
|
||||||
.borrow()
|
|
||||||
.get(&raw_fn)
|
.get(&raw_fn)
|
||||||
.and_then(|(cb, _name)| *cb)
|
.and_then(|(cb, _name)| *cb)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
|
@ -266,6 +264,8 @@ unsafe extern "C" fn napi_register_module_v1(
|
||||||
unsafe {
|
unsafe {
|
||||||
sys::setup();
|
sys::setup();
|
||||||
}
|
}
|
||||||
|
crate::__private::___CALL_FROM_FACTORY.get_or_default();
|
||||||
|
let registered_classes_ptr = REGISTERED_CLASSES.get_or_default();
|
||||||
let lock = MODULE_REGISTER_LOCK
|
let lock = MODULE_REGISTER_LOCK
|
||||||
.lock()
|
.lock()
|
||||||
.expect("Failed to acquire module register lock");
|
.expect("Failed to acquire module register lock");
|
||||||
|
@ -344,6 +344,9 @@ unsafe extern "C" fn napi_register_module_v1(
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut registered_classes: RegisteredClasses =
|
||||||
|
HashMap::with_capacity(MODULE_CLASS_PROPERTIES.borrow_mut(|inner| inner.len()));
|
||||||
|
|
||||||
MODULE_CLASS_PROPERTIES.borrow_mut(|inner| {
|
MODULE_CLASS_PROPERTIES.borrow_mut(|inner| {
|
||||||
inner.iter().for_each(|(rust_name, js_mods)| {
|
inner.iter().for_each(|(rust_name, js_mods)| {
|
||||||
for (js_mod, (js_name, props)) in js_mods {
|
for (js_mod, (js_name, props)) in js_mods {
|
||||||
|
@ -407,10 +410,7 @@ unsafe extern "C" fn napi_register_module_v1(
|
||||||
let mut ctor_ref = ptr::null_mut();
|
let mut ctor_ref = ptr::null_mut();
|
||||||
sys::napi_create_reference(env, class_ptr, 1, &mut ctor_ref);
|
sys::napi_create_reference(env, class_ptr, 1, &mut ctor_ref);
|
||||||
|
|
||||||
REGISTERED_CLASSES.with(|registered_classes| {
|
registered_classes.insert(js_name.to_string(), ctor_ref);
|
||||||
let mut registered_class = registered_classes.borrow_mut();
|
|
||||||
registered_class.insert(js_name.to_string(), ctor_ref);
|
|
||||||
});
|
|
||||||
|
|
||||||
check_status_or_throw!(
|
check_status_or_throw!(
|
||||||
env,
|
env,
|
||||||
|
@ -430,7 +430,11 @@ unsafe extern "C" fn napi_register_module_v1(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
registered_classes_ptr.store(
|
||||||
|
Box::into_raw(Box::new(registered_classes)),
|
||||||
|
Ordering::Relaxed,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "compat-mode")]
|
#[cfg(feature = "compat-mode")]
|
||||||
|
@ -462,7 +466,8 @@ pub(crate) unsafe extern "C" fn noop(
|
||||||
env: sys::napi_env,
|
env: sys::napi_env,
|
||||||
_info: sys::napi_callback_info,
|
_info: sys::napi_callback_info,
|
||||||
) -> sys::napi_value {
|
) -> sys::napi_value {
|
||||||
if !crate::bindgen_runtime::___CALL_FROM_FACTORY.with(|inner| inner.load(Ordering::Relaxed)) {
|
let inner = crate::bindgen_runtime::___CALL_FROM_FACTORY.get_or_default();
|
||||||
|
if !inner.load(Ordering::Relaxed) {
|
||||||
unsafe {
|
unsafe {
|
||||||
sys::napi_throw_error(
|
sys::napi_throw_error(
|
||||||
env,
|
env,
|
||||||
|
|
|
@ -75,7 +75,6 @@
|
||||||
|
|
||||||
#[cfg(feature = "napi8")]
|
#[cfg(feature = "napi8")]
|
||||||
mod async_cleanup_hook;
|
mod async_cleanup_hook;
|
||||||
|
|
||||||
#[cfg(feature = "napi8")]
|
#[cfg(feature = "napi8")]
|
||||||
pub use async_cleanup_hook::AsyncCleanupHook;
|
pub use async_cleanup_hook::AsyncCleanupHook;
|
||||||
mod async_work;
|
mod async_work;
|
||||||
|
@ -86,7 +85,6 @@ mod cleanup_env;
|
||||||
mod env;
|
mod env;
|
||||||
mod error;
|
mod error;
|
||||||
mod js_values;
|
mod js_values;
|
||||||
|
|
||||||
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
||||||
mod promise;
|
mod promise;
|
||||||
mod status;
|
mod status;
|
||||||
|
@ -169,7 +167,7 @@ pub mod bindgen_prelude {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod __private {
|
pub mod __private {
|
||||||
pub use crate::bindgen_runtime::{
|
pub use crate::bindgen_runtime::{
|
||||||
get_class_constructor, iterator::create_iterator, register_class,
|
get_class_constructor, iterator::create_iterator, register_class, ___CALL_FROM_FACTORY,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::sys;
|
use crate::sys;
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
//! The following directly was copied from [neon][].
|
|
||||||
//!
|
|
||||||
//! Rust port of [win_delay_load_hook.cc][].
|
|
||||||
//!
|
|
||||||
//! When the addon tries to load the "node.exe" DLL module, this module gives it the pointer to the
|
|
||||||
//! .exe we are running in instead. Typically, that will be the same value. But if the node executable
|
|
||||||
//! was renamed, you would not otherwise get the correct DLL.
|
|
||||||
//!
|
|
||||||
//! [neon]: https://github.com/neon-bindings/neon/blob/5ffa2d282177b63094c46e92b20b8e850d122e65/src/win_delay_load_hook.rs
|
|
||||||
//! [win_delay_load_hook.cc]: https://github.com/nodejs/node-gyp/blob/e18a61afc1669d4897e6c5c8a6694f4995a0f4d6/src/win_delay_load_hook.cc
|
|
||||||
|
|
||||||
use std::ffi::CStr;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
|
|
||||||
use windows::core::PCSTR;
|
|
||||||
use windows::Win32::Foundation::HINSTANCE;
|
|
||||||
use windows::Win32::System::LibraryLoader::GetModuleHandleA;
|
|
||||||
use windows::Win32::System::WindowsProgramming::{DELAYLOAD_INFO, PDELAYLOAD_FAILURE_DLL_CALLBACK};
|
|
||||||
|
|
||||||
// Structures hand-copied from
|
|
||||||
// https://docs.microsoft.com/en-us/cpp/build/reference/structure-and-constant-definitions
|
|
||||||
|
|
||||||
const HOST_BINARIES: &[&[u8]] = &[b"node.exe", b"electron.exe"];
|
|
||||||
|
|
||||||
unsafe extern "C" fn load_exe_hook(event: u32, info: *const DELAYLOAD_INFO) -> HINSTANCE {
|
|
||||||
if event != 0x01
|
|
||||||
/* dliNotePreLoadLibrary */
|
|
||||||
{
|
|
||||||
return HINSTANCE::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
let dll_name = unsafe { CStr::from_ptr((*info).TargetDllName.0 as *mut i8) };
|
|
||||||
if !HOST_BINARIES
|
|
||||||
.iter()
|
|
||||||
.any(|&host_name| host_name == dll_name.to_bytes())
|
|
||||||
{
|
|
||||||
return HINSTANCE::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
match unsafe { GetModuleHandleA(PCSTR::default()) } {
|
|
||||||
Ok(h) => h,
|
|
||||||
Err(e) => unsafe {
|
|
||||||
let location = "win_delay_load_hook.rs\0";
|
|
||||||
let err = format!("{}", e);
|
|
||||||
crate::sys::napi_fatal_error(
|
|
||||||
location.as_ptr() as *const c_char,
|
|
||||||
22,
|
|
||||||
format!("{}\0", err).as_ptr() as *const c_char,
|
|
||||||
err.len(),
|
|
||||||
);
|
|
||||||
unreachable!();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
static mut __pfnDliNotifyHook2: *mut PDELAYLOAD_FAILURE_DLL_CALLBACK =
|
|
||||||
load_exe_hook as *mut PDELAYLOAD_FAILURE_DLL_CALLBACK;
|
|
|
@ -35,7 +35,19 @@ macro_rules! generate {
|
||||||
) -> Result<(), libloading::Error> {
|
) -> Result<(), libloading::Error> {
|
||||||
NAPI = Napi {
|
NAPI = Napi {
|
||||||
$(
|
$(
|
||||||
$name: *host.get(stringify!($name).as_bytes())?,
|
$name: {
|
||||||
|
let symbol: Result<libloading::Symbol<unsafe extern "C" fn ($(_: $ptype,)*)$( -> $rtype)*>, libloading::Error> = host.get(stringify!($name).as_bytes());
|
||||||
|
match symbol {
|
||||||
|
Ok(f) => *f,
|
||||||
|
Err(e) => {
|
||||||
|
debug_assert!({
|
||||||
|
println!("Load Node-API [{}] from host runtime failed: {}", stringify!($name), e);
|
||||||
|
true
|
||||||
|
});
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,6 +56,7 @@ macro_rules! generate {
|
||||||
|
|
||||||
$(
|
$(
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::missing_safety_doc)]
|
||||||
pub unsafe fn $name($($param: $ptype,)*)$( -> $rtype)* {
|
pub unsafe fn $name($($param: $ptype,)*)$( -> $rtype)* {
|
||||||
(NAPI.$name)($($param,)*)
|
(NAPI.$name)($($param,)*)
|
||||||
}
|
}
|
||||||
|
@ -81,6 +94,7 @@ static SETUP: Once = Once::new();
|
||||||
/// they will panic.
|
/// they will panic.
|
||||||
/// Safety: `env` must be a valid `napi_env` for the current thread
|
/// Safety: `env` must be a valid `napi_env` for the current thread
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
#[allow(clippy::missing_safety_doc)]
|
||||||
pub unsafe fn setup() {
|
pub unsafe fn setup() {
|
||||||
SETUP.call_once(|| {
|
SETUP.call_once(|| {
|
||||||
if let Err(err) = load() {
|
if let Err(err) = load() {
|
||||||
|
|
Loading…
Reference in a new issue