diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 282844da0..0f334d178 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -63,11 +63,6 @@ nix = "=0.30.1" [target.'cfg(windows)'.dependencies] libc = "0.2.172" -windows-sys = { version = "0.60.2", features = [ - "Win32_Foundation", - "Win32_System_Console", - "Win32_System_Threading" # for using CreateProcess flags like CREATE_NEW_PROCESS_GROUP -] } [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-updater = "2" diff --git a/src-tauri/src/core/utils/extensions/inference_llamacpp_extension/cleanup.rs b/src-tauri/src/core/utils/extensions/inference_llamacpp_extension/cleanup.rs index 5e5a08fc5..be7dde514 100644 --- a/src-tauri/src/core/utils/extensions/inference_llamacpp_extension/cleanup.rs +++ b/src-tauri/src/core/utils/extensions/inference_llamacpp_extension/cleanup.rs @@ -1,5 +1,5 @@ -use tauri::State; use crate::core::state::AppState; +use tauri::State; pub async fn cleanup_processes(state: State<'_, AppState>) { let mut map = state.llama_server_process.lock().await; @@ -19,8 +19,12 @@ pub async fn cleanup_processes(state: State<'_, AppState>) { let _ = kill(Pid::from_raw(raw_pid), Signal::SIGTERM); match timeout(Duration::from_secs(2), child.wait()).await { - Ok(Ok(status)) => log::info!("Process {} exited gracefully: {}", raw_pid, status), - Ok(Err(e)) => log::error!("Error waiting after SIGTERM for {}: {}", raw_pid, e), + Ok(Ok(status)) => { + log::info!("Process {} exited gracefully: {}", raw_pid, status) + } + Ok(Err(e)) => { + log::error!("Error waiting after SIGTERM for {}: {}", raw_pid, e) + } Err(_) => { log::warn!("SIGTERM timed out for PID {}; sending SIGKILL", raw_pid); let _ = kill(Pid::from_raw(raw_pid), Signal::SIGKILL); @@ -29,27 +33,31 @@ pub async fn cleanup_processes(state: State<'_, AppState>) { } } } - #[cfg(all(windows, target_arch = "x86_64"))] { - use windows_sys::Win32::System::Console::{GenerateConsoleCtrlEvent, CTRL_C_EVENT}; - use tokio::time::{timeout, Duration}; - if let Some(raw_pid) = child.id() { - log::info!("Sending Ctrl-C to PID {} during shutdown", raw_pid); - let ok: i32 = unsafe { GenerateConsoleCtrlEvent(CTRL_C_EVENT, raw_pid) }; - if ok == 0 { - log::error!("Failed to send Ctrl-C to PID {}", raw_pid); - } + log::warn!( + "Gracefully terminating is unsupported on Windows, force-killing PID {}", + raw_pid + ); - match timeout(Duration::from_secs(2), child.wait()).await { - Ok(Ok(status)) => log::info!("Process {} exited after Ctrl-C: {}", raw_pid, status), - Ok(Err(e)) => log::error!("Error waiting after Ctrl-C for {}: {}", raw_pid, e), - Err(_) => { - log::warn!("Timed out for PID {}; force-killing", raw_pid); - let _ = child.kill().await; - let _ = child.wait().await; - } + // Since we know a graceful shutdown doesn't work and there are no child processes + // to worry about, we can use `child.kill()` directly. On Windows, this is + // a forceful termination via the `TerminateProcess` API. + if let Err(e) = child.kill().await { + log::error!("Failed to send kill signal to PID {}: {}. It may have already terminated.", raw_pid, e); + } + match child.wait().await { + Ok(status) => log::info!( + "process {} has been terminated. Final exit status: {}", + raw_pid, + status + ), + Err(e) => log::error!( + "Error waiting on child process {} after kill: {}", + raw_pid, + e + ), } } } diff --git a/src-tauri/src/core/utils/extensions/inference_llamacpp_extension/server.rs b/src-tauri/src/core/utils/extensions/inference_llamacpp_extension/server.rs index 83e4c8fc2..338e8aa30 100644 --- a/src-tauri/src/core/utils/extensions/inference_llamacpp_extension/server.rs +++ b/src-tauri/src/core/utils/extensions/inference_llamacpp_extension/server.rs @@ -330,35 +330,34 @@ pub async fn unload_llama_model( #[cfg(all(windows, target_arch = "x86_64"))] { - use windows_sys::Win32::System::Console::{GenerateConsoleCtrlEvent, CTRL_C_EVENT}; - if let Some(raw_pid) = child.id() { - log::info!("Sending Ctrl-C to PID {}", raw_pid); - let ok: i32 = unsafe { GenerateConsoleCtrlEvent(CTRL_C_EVENT, raw_pid as u32) }; - if ok == 0 { - log::error!("Failed to send Ctrl-C to PID {}", raw_pid); + log::warn!("gracefully killing is unsupported on Windows, force-killing PID {}", raw_pid); + + // Since we know a graceful shutdown doesn't work and there are no child processes + // to worry about, we can use `child.kill()` directly. On Windows, this is + // a forceful termination via the `TerminateProcess` API. + if let Err(e) = child.kill().await { + log::error!( + "Failed to send kill signal to PID {}: {}. It may have already terminated.", + raw_pid, + e + ); } - match timeout(Duration::from_secs(5), child.wait()).await { - Ok(Ok(status)) => log::info!("Process exited after Ctrl-C: {}", status), - Ok(Err(e)) => log::error!("Error waiting after Ctrl-C: {}", e), - Err(_) => { - log::warn!("Timed out; force-killing PID {}", raw_pid); - if let Err(e) = child.kill().await { - log::error!("Failed to kill process {}: {}", raw_pid, e); - return Ok(UnloadResult { - success: false, - error: Some(format!("kill failed: {}", e)), - }); - } - if let Ok(s) = child.wait().await { - log::info!("Process finally exited: {}", s); - } - } + match child.wait().await { + Ok(status) => log::info!( + "process {} has been terminated. Final exit status: {}", + raw_pid, + status + ), + Err(e) => log::error!( + "Error waiting on child process {} after kill: {}", + raw_pid, + e + ), } } } - Ok(UnloadResult { success: true, error: None,