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!( {
sys::napi_add_env_cleanup_hook(env, Some(crate::shutdown_tokio_rt), ptr::null_mut()), let _ = crate::tokio_runtime::RT.clone();
"Failed to initialize module", crate::tokio_runtime::TOKIO_RT_REF_COUNT.fetch_add(1, Ordering::Relaxed);
) { assert_eq!(
JsError::from(e).throw_into(env); sys::napi_add_env_cleanup_hook(env, Some(crate::shutdown_tokio_rt), ptr::null_mut()),
sys::Status::napi_ok
);
} }
exports exports

View file

@ -1,35 +1,52 @@
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! {
let runtime = tokio::runtime::Runtime::new(); pub(crate) static ref RT: (Handle, mpsc::Sender<()>) = {
let (sender, mut receiver) = mpsc::channel::<()>(1); let runtime = tokio::runtime::Runtime::new();
runtime let (sender, mut receiver) = mpsc::channel::<()>(1);
.map(|rt| { runtime
let h = rt.handle(); .map(|rt| {
let handle = h.clone(); let h = rt.handle();
handle.spawn(async move { let handle = h.clone();
if receiver.recv().await.is_some() { handle.spawn(async move {
rt.shutdown_background(); if receiver.recv().await.is_some() {
} rt.shutdown_background();
}); }
});
(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) {
let sender = &RT.1; if TOKIO_RT_REF_COUNT.fetch_sub(1, Ordering::Relaxed) == 0 {
sender let sender = &RT.1;
.clone() if let Err(e) = sender.clone().try_send(()) {
.try_send(()) match e {
.expect("Shutdown tokio runtime failed"); TrySendError::Closed(_) => {}
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)