G3.2+G3.3: classify hang/crash vs audio stall + SEH per-channel plugin crash isolation (mute channel)

This commit is contained in:
2026-08-16 10:23:08 +07:00
parent 30fa98a441
commit 0b8e80fe2c
6 changed files with 186 additions and 8 deletions
+1
View File
@@ -23,6 +23,7 @@ windows-sys = { version = "0.59", features = [
"Win32_Foundation",
"Win32_Security",
"Win32_System_Memory",
"Win32_System_Threading",
] }
[profile.release]
+33 -2
View File
@@ -95,6 +95,21 @@ fn kill_process_tree(child: &CommandChild) -> bool {
.unwrap_or(false)
}
/// G3.2: true if a process with `pid` still exists (OpenProcess + exit code).
/// Used to classify a stalled heartbeat: pid alive = HANG, pid gone = CRASH.
fn process_alive(pid: u32) -> bool {
use windows_sys::Win32::Foundation::STILL_ACTIVE;
use windows_sys::Win32::System::Threading::{GetExitCodeProcess, OpenProcess};
let handle = unsafe { OpenProcess(windows_sys::Win32::System::Threading::PROCESS_QUERY_LIMITED_INFORMATION, 0, pid) };
if handle.is_null() {
return false; // not found or no access -> treat as gone
}
let mut code: u32 = 0;
let ok = unsafe { GetExitCodeProcess(handle, &mut code) } != 0;
unsafe { windows_sys::Win32::Foundation::CloseHandle(handle) };
ok && code == STILL_ACTIVE as u32
}
/// Audio frame pushed to the WebView (bridge SHM -> `bridge-audio` event).
#[derive(Clone, serde::Serialize)]
struct AudioFrame {
@@ -478,8 +493,24 @@ pub fn run() {
let log_dir = std::env::var("APPDATA").unwrap_or_else(|_| ".".into());
let log_path = std::path::Path::new(&log_dir)
.join("SonicForgeDAW").join("logs").join("spawn.log");
let mut line = String::from("[tauri] bridge heartbeat stalled 3s — restart attempt #1
");
// G3.2: phân loại stall — process còn sống = HANG
// (heartbeat thread kẹt), pid biến mất = CRASH.
let pid = pump_handle
.state::<BridgeProcess>()
.0
.lock()
.ok()
.and_then(|g| g.as_ref().map(|c| c.pid()));
let kind = match pid {
Some(p) if process_alive(p) => {
format!("HUNG (pid {p} alive, heartbeat stalled)")
}
Some(p) => format!("CRASHED (pid {p} gone)"),
None => "UNKNOWN (no tracked pid)".into(),
};
let mut line = format!(
"[tauri] bridge heartbeat stalled 3s — {kind} — restart attempt #1\n"
);
// FIX: kill bridge cũ trước — không được để 2 bridge
// cùng map SHM (race control queue / double load).
kill_bridge(&pump_handle);