fix(napi): only shutdown tokio runtime once

This commit is contained in:
LongYinan 2021-12-21 23:22:23 +08:00
parent 13c9437b61
commit 915b423026
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
2 changed files with 48 additions and 29 deletions

View file

@ -238,11 +238,13 @@ unsafe extern "C" fn napi_register_module_v1(
}); });
#[cfg(all(feature = "tokio_rt", feature = "napi4"))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
if let Err(e) = check_status!( {
let _ = crate::tokio_runtime::RT.clone();
crate::tokio_runtime::TOKIO_RT_REF_COUNT.fetch_add(1, Ordering::Relaxed);
assert_eq!(
sys::napi_add_env_cleanup_hook(env, Some(crate::shutdown_tokio_rt), ptr::null_mut()), sys::napi_add_env_cleanup_hook(env, Some(crate::shutdown_tokio_rt), ptr::null_mut()),
"Failed to initialize module", sys::Status::napi_ok
) { );
JsError::from(e).throw_into(env);
} }
exports exports

View file

@ -1,10 +1,18 @@
use std::{ffi::c_void, future::Future, ptr}; use std::ffi::c_void;
use std::future::Future;
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
use lazy_static::lazy_static;
use tokio::{
runtime::Handle,
sync::mpsc::{self, error::TrySendError},
};
use crate::{check_status, promise, sys, Result}; use crate::{check_status, promise, sys, Result};
use once_cell::sync::Lazy;
use tokio::{runtime::Handle, sync::mpsc};
static RT: Lazy<(Handle, mpsc::Sender<()>)> = Lazy::new(|| { lazy_static! {
pub(crate) static ref RT: (Handle, mpsc::Sender<()>) = {
let runtime = tokio::runtime::Runtime::new(); let runtime = tokio::runtime::Runtime::new();
let (sender, mut receiver) = mpsc::channel::<()>(1); let (sender, mut receiver) = mpsc::channel::<()>(1);
runtime runtime
@ -20,16 +28,25 @@ static RT: Lazy<(Handle, mpsc::Sender<()>)> = Lazy::new(|| {
(handle, sender) (handle, sender)
}) })
.expect("Create tokio runtime failed") .expect("Create tokio runtime failed")
}); };
}
pub(crate) static TOKIO_RT_REF_COUNT: AtomicUsize = AtomicUsize::new(0);
#[doc(hidden)] #[doc(hidden)]
#[inline(never)] #[inline(never)]
pub extern "C" fn shutdown_tokio_rt(_arg: *mut c_void) { pub extern "C" fn shutdown_tokio_rt(_arg: *mut c_void) {
if TOKIO_RT_REF_COUNT.fetch_sub(1, Ordering::Relaxed) == 0 {
let sender = &RT.1; let sender = &RT.1;
sender if let Err(e) = sender.clone().try_send(()) {
.clone() match e {
.try_send(()) TrySendError::Closed(_) => {}
.expect("Shutdown tokio runtime failed"); TrySendError::Full(_) => {
panic!("Send shutdown signal to tokio runtime failed, queue is full");
}
}
}
}
} }
pub fn spawn<F>(fut: F) pub fn spawn<F>(fut: F)