chore(napi): reduce the complex about destroying tokio runtime
This commit is contained in:
parent
a9f9dbb232
commit
c01bcecb2b
3 changed files with 19 additions and 55 deletions
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
examples/napi/__test__/unload.spec.js
Normal file
11
examples/napi/__test__/unload.spec.js
Normal 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)
|
||||||
|
})
|
Loading…
Reference in a new issue