diff --git a/src/bin/main.rs b/src/bin/main.rs index c024e14..bc85f04 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -26,11 +26,12 @@ fn main() -> Result<(), BoxError> { let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?; rt.block_on(async move { let res = main_async(args).await; - // Start a timer to force exit after FORCE_EXIT_TIMEOUT second - let _h = tokio::spawn(async move { - log::info!("Starting {}-seconds exit timer", tun2proxy::FORCE_EXIT_TIMEOUT); + // Start a timer to force exit after FORCE_EXIT_TIMEOUT seconds. Use a std thread + // so the timer is not cancelled when the tokio runtime is being shut down. + let _h = std::thread::spawn(move || { + log::info!("Starting {:?} exit timer", tun2proxy::FORCE_EXIT_TIMEOUT); // Delay some seconds then try to exit current process if not exited yet, normally this case should not happen - tokio::time::sleep(std::time::Duration::from_secs(tun2proxy::FORCE_EXIT_TIMEOUT)).await; + std::thread::sleep(tun2proxy::FORCE_EXIT_TIMEOUT); log::info!("Forcing exit now."); std::process::exit(-1); }); diff --git a/src/general_api.rs b/src/general_api.rs index 64895b3..e5587ef 100644 --- a/src/general_api.rs +++ b/src/general_api.rs @@ -132,9 +132,11 @@ pub fn general_run_for_api(args: Args, tun_mtu: u16, packet_information: bool) - let args_clone = args.clone(); let res = rt.block_on(async move { let ret = general_run_async(args_clone, tun_mtu, packet_information, shutdown_token).await; - let _h = tokio::spawn(async move { + // Spawn a std thread to force exit after timeout so it isn't cancelled + // when the tokio runtime is dropped. + let _h = std::thread::spawn(move || { // Delay some seconds then try to exit current process if not exited yet, normally this case should not happen - tokio::time::sleep(std::time::Duration::from_secs(crate::FORCE_EXIT_TIMEOUT)).await; + std::thread::sleep(crate::FORCE_EXIT_TIMEOUT); log::info!("Forcing exit now."); std::process::exit(-1); }); diff --git a/src/lib.rs b/src/lib.rs index 0c61856..dd3a1b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; pub use general_api::general_run_async; -pub const FORCE_EXIT_TIMEOUT: u64 = 2; // seconds +pub const FORCE_EXIT_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(2); mod android; mod args; diff --git a/src/win_svc.rs b/src/win_svc.rs index 48f2457..389bddf 100644 --- a/src/win_svc.rs +++ b/src/win_svc.rs @@ -83,9 +83,10 @@ fn run_service(_arguments: Vec) -> Result<(), crate::BoxErro Ok(sessions) => log::debug!("tun2proxy exited normally, current session count: {sessions}"), Err(e) => log::error!("failed to run tun2proxy with error: {e:?}"), } - let _h = tokio::spawn(async move { + // Spawn a std thread so the timer survives runtime shutdown and reliably exits. + let _h = std::thread::spawn(move || { // Delay some seconds then try to exit current process if not exited yet, normally this case should not happen - tokio::time::sleep(std::time::Duration::from_secs(crate::FORCE_EXIT_TIMEOUT)).await; + std::thread::sleep(crate::FORCE_EXIT_TIMEOUT); log::info!("Forcing exit now."); std::process::exit(-1); });