chore(napi): reduce the complex about destroying tokio runtime

This commit is contained in:
LongYinan 2022-12-16 14:32:01 +08:00
parent a9f9dbb232
commit c01bcecb2b
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
3 changed files with 19 additions and 55 deletions

View file

@ -1,5 +1,5 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ffi::{c_void, CStr}; use std::ffi::CStr;
use std::ptr; use std::ptr;
use std::sync::atomic::AtomicUsize; use std::sync::atomic::AtomicUsize;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
@ -473,27 +473,10 @@ unsafe extern "C" fn napi_register_module_v1(
}) })
}); });
#[cfg(feature = "napi3")]
{
unsafe {
sys::napi_add_env_cleanup_hook(env, Some(remove_registered_classes), env as *mut c_void)
};
}
REGISTERED.store(true, Ordering::SeqCst); REGISTERED.store(true, Ordering::SeqCst);
exports exports
} }
unsafe extern "C" fn remove_registered_classes(env: *mut c_void) {
let env = env as sys::napi_env;
if let Some(s) = REGISTERED_CLASSES.get() {
let registered_classes = unsafe { Box::from_raw(s.load(Ordering::Relaxed)) };
registered_classes.iter().for_each(|(_, v)| {
unsafe { sys::napi_delete_reference(env, *v) };
});
s.store(ptr::null_mut(), Ordering::Relaxed);
}
}
pub(crate) unsafe extern "C" fn noop( 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,

View file

@ -2,43 +2,12 @@ use std::future::Future;
use std::ptr; use std::ptr;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use tokio::{ use tokio::runtime::Runtime;
runtime::Handle,
sync::mpsc::{self, error::TrySendError},
};
use crate::{check_status, sys, JsDeferred, JsUnknown, NapiValue, Result}; use crate::{check_status, sys, JsDeferred, JsUnknown, NapiValue, Result};
pub(crate) static RT: Lazy<(Handle, mpsc::Sender<()>)> = Lazy::new(|| { pub(crate) static RT: Lazy<Runtime> =
let runtime = tokio::runtime::Runtime::new(); Lazy::new(|| tokio::runtime::Runtime::new().expect("Create tokio runtime failed"));
let (sender, mut receiver) = mpsc::channel::<()>(1);
runtime
.map(|rt| {
let h = rt.handle();
let handle = h.clone();
handle.spawn(async move {
if receiver.recv().await.is_some() {
rt.shutdown_background();
}
});
(handle, sender)
})
.expect("Create tokio runtime failed")
});
#[ctor::dtor]
fn shutdown_tokio() {
let sender = &RT.1;
if let Err(e) = sender.clone().try_send(()) {
match e {
TrySendError::Closed(_) => {}
TrySendError::Full(_) => {
panic!("Send shutdown signal to tokio runtime failed, queue is full");
}
}
}
}
/// Spawns a future onto the Tokio runtime. /// Spawns a future onto the Tokio runtime.
/// ///
@ -48,7 +17,7 @@ pub fn spawn<F>(fut: F) -> tokio::task::JoinHandle<F::Output>
where where
F: 'static + Send + Future<Output = ()>, F: 'static + Send + Future<Output = ()>,
{ {
RT.0.spawn(fut) RT.spawn(fut)
} }
/// Runs a future to completion /// Runs a future to completion
@ -58,7 +27,7 @@ pub fn block_on<F>(fut: F) -> F::Output
where where
F: 'static + Send + Future<Output = ()>, F: 'static + Send + Future<Output = ()>,
{ {
RT.0.block_on(fut) RT.block_on(fut)
} }
// This function's signature must be kept in sync with the one in lib.rs, otherwise napi // This function's signature must be kept in sync with the one in lib.rs, otherwise napi
@ -66,8 +35,9 @@ where
/// If the feature `tokio_rt` has been enabled this will enter the runtime context and /// If the feature `tokio_rt` has been enabled this will enter the runtime context and
/// then call the provided closure. Otherwise it will just call the provided closure. /// then call the provided closure. Otherwise it will just call the provided closure.
#[inline]
pub fn within_runtime_if_available<F: FnOnce() -> T, T>(f: F) -> T { pub fn within_runtime_if_available<F: FnOnce() -> T, T>(f: F) -> T {
let _rt_guard = RT.0.enter(); let _rt_guard = RT.enter();
f() f()
} }

View file

@ -0,0 +1,11 @@
// use the commonjs syntax to prevent compiler from transpiling the module syntax
const test = require('ava').default
test('unload module', (t) => {
const { add } = require('../index.node')
t.is(add(1, 2), 3)
delete require.cache[require.resolve('../index.node')]
const { add: add2 } = require('../index.node')
t.is(add2(1, 2), 3)
})