perf: Optimize kernel shutdown speed & logic

This commit is contained in:
wonfen 2025-02-10 13:18:00 +08:00
parent 89d9f47191
commit e5af9541da

View File

@ -5,7 +5,6 @@ use sysinfo::{Pid, System, Signal};
use crate::utils::dirs; use crate::utils::dirs;
use std::time::Duration; use std::time::Duration;
const TERM_WAIT: Duration = Duration::from_millis(500);
const KILL_WAIT: Duration = Duration::from_millis(500); const KILL_WAIT: Duration = Duration::from_millis(500);
const FINAL_WAIT: Duration = Duration::from_millis(1000); const FINAL_WAIT: Duration = Duration::from_millis(1000);
@ -23,68 +22,49 @@ impl ProcessLock {
} }
fn is_target_process(process_name: &str) -> bool { fn is_target_process(process_name: &str) -> bool {
(process_name.contains("mihomo") || process_name.contains("clash")) let name = process_name.to_lowercase();
&& !process_name.contains("clash-verge") (name.contains("mihomo") || name.contains("clash"))
&& !process_name.contains("clash.meta") && !name.contains("clash-verge")
&& !name.contains("clash.meta")
} }
fn kill_process(pid: Pid, process: &sysinfo::Process) -> bool { fn kill_process(pid: Pid, process: &sysinfo::Process) -> bool {
let process_name = process.name().to_string_lossy().to_lowercase(); let process_name = process.name().to_string_lossy().to_lowercase();
let process_pid = pid.as_u32(); let process_pid = pid.as_u32();
println!("Terminating clash core process (PID: {}, Name: {})", process_pid, process_name); println!("Force killing process (PID: {}, Name: {})", process_pid, process_name);
log::info!(target: "app", "Terminating clash core process (PID: {}, Name: {})", process_pid, process_name); log::info!(target: "app", "Force killing process (PID: {}, Name: {})", process_pid, process_name);
// 首先尝试正常终止
#[cfg(not(target_os = "windows"))]
{
println!("Sending SIGTERM to process {}", process_pid);
log::info!(target: "app", "Sending SIGTERM to process {}", process_pid);
let _ = process.kill_with(Signal::Term);
}
#[cfg(target_os = "windows")]
{
println!("Killing process {}", process_pid);
log::info!(target: "app", "Killing process {}", process_pid);
process.kill();
}
std::thread::sleep(TERM_WAIT);
// 检查进程是否还在运行
let mut new_sys = System::new();
new_sys.refresh_all();
if let Some(p) = new_sys.process(pid) {
println!("Process {} still running, trying force kill", process_pid);
log::info!(target: "app", "Process {} still running, trying force kill", process_pid);
// 直接使用 SIGKILL 强制终止
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
{ {
println!("Sending SIGKILL to process {}", process_pid); println!("Sending SIGKILL to process {}", process_pid);
log::info!(target: "app", "Sending SIGKILL to process {}", process_pid); log::info!(target: "app", "Sending SIGKILL to process {}", process_pid);
let _ = p.kill_with(Signal::Kill); let _ = process.kill_with(Signal::Kill);
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {
println!("Force killing process {}", process_pid); println!("Force killing process {}", process_pid);
log::info!(target: "app", "Force killing process {}", process_pid); log::info!(target: "app", "Force killing process {}", process_pid);
p.kill(); process.kill();
} }
std::thread::sleep(KILL_WAIT); std::thread::sleep(KILL_WAIT);
// 再次检查进程是否存在 // 检查进程是否还在运行
new_sys.refresh_all(); let mut sys = System::new();
if new_sys.process(pid).is_some() { sys.refresh_all();
let is_terminated = sys.process(pid).is_none();
if !is_terminated {
println!("Failed to terminate process {}", process_pid); println!("Failed to terminate process {}", process_pid);
log::error!(target: "app", "Failed to terminate process {}", process_pid); log::error!(target: "app", "Failed to terminate process {}", process_pid);
return false; } else {
}
}
println!("Process {} has been terminated", process_pid); println!("Process {} has been terminated", process_pid);
log::info!(target: "app", "Process {} has been terminated", process_pid); log::info!(target: "app", "Process {} has been terminated", process_pid);
true }
is_terminated
} }
fn kill_other_processes(include_current: bool) -> Result<()> { fn kill_other_processes(include_current: bool) -> Result<()> {
@ -95,48 +75,48 @@ impl ProcessLock {
sys.refresh_all(); sys.refresh_all();
let current_pid = std::process::id(); let current_pid = std::process::id();
println!("Current process ID: {}", current_pid);
log::info!(target: "app", "Current process ID: {}", current_pid);
let mut killed = false;
let mut failed_kills = Vec::new(); let mut failed_kills = Vec::new();
for (pid, process) in sys.processes() { // 收集需要终止的进程
let process_name = process.name().to_string_lossy().to_lowercase(); let target_processes: Vec<_> = sys.processes()
if Self::is_target_process(&process_name) {
let process_pid = pid.as_u32();
if include_current || process_pid != current_pid {
if !Self::kill_process(*pid, process) {
failed_kills.push((process_pid, process_name.clone()));
}
killed = true;
}
}
}
if killed {
std::thread::sleep(FINAL_WAIT);
// 最终检查
let mut final_sys = System::new();
final_sys.refresh_all();
let remaining: Vec<_> = final_sys.processes()
.iter() .iter()
.filter(|(_, process)| { .filter(|(pid, process)| {
let name = process.name().to_string_lossy().to_lowercase(); let process_pid = pid.as_u32();
Self::is_target_process(&name) let process_name = process.name().to_string_lossy();
})
.map(|(pid, process)| { Self::is_target_process(&process_name) &&
(pid.as_u32(), process.name().to_string_lossy().to_string()) (include_current || process_pid != current_pid)
}) })
.collect(); .collect();
if !remaining.is_empty() { // 如果没有目标进程,直接返回
log::error!(target: "app", "Failed to terminate some processes: {:?}", remaining); if target_processes.is_empty() {
bail!("Failed to terminate processes: {:?}", remaining); println!("No target processes found");
log::info!(target: "app", "No target processes found");
return Ok(());
} }
// 终止进程
for (pid, process) in target_processes {
if !Self::kill_process(*pid, process) {
failed_kills.push((pid.as_u32(), process.name().to_string_lossy().to_string()));
}
}
// 最终检查
std::thread::sleep(FINAL_WAIT);
sys.refresh_all();
let remaining: Vec<_> = sys.processes()
.iter()
.filter(|(_, process)| Self::is_target_process(&process.name().to_string_lossy()))
.map(|(pid, process)| (pid.as_u32(), process.name().to_string_lossy().to_string()))
.collect();
if !remaining.is_empty() {
println!("Failed to terminate processes: {:?}", remaining);
log::error!(target: "app", "Failed to terminate processes: {:?}", remaining);
bail!("Failed to terminate processes: {:?}", remaining);
} }
println!("Process cleanup completed"); println!("Process cleanup completed");
@ -181,7 +161,6 @@ impl ProcessLock {
impl Drop for ProcessLock { impl Drop for ProcessLock {
fn drop(&mut self) { fn drop(&mut self) {
// 只在 PID 文件还存在时执行释放
if self.pid_file.exists() { if self.pid_file.exists() {
println!("ProcessLock being dropped"); println!("ProcessLock being dropped");
log::info!(target: "app", "ProcessLock being dropped"); log::info!(target: "app", "ProcessLock being dropped");