fix(state_portal): make shutdown() idempotent to prevent duplicate log lines (#22)

shutdown() fired twice on exit (explicit call in main.rs + Drop impl), causing "Total: N frames" and "StatePortal shutdown complete" to log twice 23us apart. Add `shutdown_started: bool` guard at function entry.

Plain bool (not AtomicBool) because &mut self already grants exclusive access. Guard is set BEFORE cleanup so Drop re-entry during panic unwinding is suppressed.

Includes scripts/test_shutdown_idempotency.sh as a live regression test (requires Wayland session). Verified PASS on KWin: both lines print exactly once.
This commit is contained in:
dailz
2026-06-20 18:45:53 +08:00
parent 0aba0e651e
commit 92760dd8ee
2 changed files with 159 additions and 2 deletions
+9 -2
View File
@@ -66,6 +66,7 @@ pub struct StatePortal {
last_fillable_frame: Option<CpuNv12Frame>, // cached last frame for filler duplication
next_filler_at: Option<Instant>, // when to send next filler frame
filler_frames_sent: u64,
shutdown_started: bool, // idempotency guard; plain bool because &mut self is exclusive (not AtomicBool)
}
impl StatePortal {
@@ -112,6 +113,7 @@ impl StatePortal {
last_fillable_frame: None,
next_filler_at: None,
filler_frames_sent: 0,
shutdown_started: false,
})
}
@@ -586,10 +588,15 @@ impl StatePortal {
Ok(())
}
/// 关闭状态:刷新编码器并清理资源
/// 关闭状态:刷新编码器并清理资源(幂等)。
///
/// 使用 `enc.take()` 确保编码器只被 flush 一次,即使多次调用也安全(幂等)
/// `shutdown_started` 守卫在清理之前置位——防止 panic 时 `Drop` 重入 unwinding
pub fn shutdown(&mut self) {
if self.shutdown_started {
return;
}
self.shutdown_started = true;
self.last_fillable_frame = None;
// 1. Stop encode thread (drops webrtc_tx → signals WebRTC thread to exit)
if let Some(mut enc_thread) = self.enc_thread.take() {