on main help sign in
fix: fixed the race condition brought by shutdown triggerred while vm input channel is not ready or closed
commit15245fd2458d23c12c09392844c1127ba3bbc45d authorrobcholz <84130577+robcholz@users.noreply.github.com> dateSun 8 Feb 2026, 02:51 (8 months ago) parent1c5a464
1 file changed+34−4
src/vm_manager.rs+34−4
src/vm_manager.rs+34−4
@@ -30,6 +30,7 @@ use crate::{
3030
3131const VM_MANAGER_LOCK_NAME: &str = "vm.lock";
3232const VM_MANAGER_LOG_NAME: &str = "vm_manager.log";
33+const HARD_SHUTDOWN_TIMEOUT_MS: u64 = 12_000;
3334
3435pub fn ensure_manager(
3536 raw_args: &[std::ffi::OsString],
@@ -721,7 +722,9 @@ fn manager_event_loop(
721722 let mut ref_count: usize = 0;
722723 let mut shutdown_deadline: Option<Instant> = None;
723724 let mut shutdown_sent = false;
725+ let mut hard_deadline: Option<Instant> = None;
724726 let grace = Duration::from_millis(auto_shutdown_ms.max(1));
727+ let hard_timeout = Duration::from_millis(HARD_SHUTDOWN_TIMEOUT_MS);
725728
726729 loop {
727730 let timeout = match shutdown_deadline {
@@ -740,6 +743,7 @@ fn manager_event_loop(
740743 );
741744 shutdown_deadline = None;
742745 shutdown_sent = false;
746+ hard_deadline = None;
743747 }
744748 Ok(ManagerEvent::Dec(pid)) => {
745749 ref_count = ref_count.saturating_sub(1);
@@ -765,12 +769,38 @@ fn manager_event_loop(
765769 && Instant::now() >= deadline
766770 && !shutdown_sent
767771 {
772+ let mut sent = false;
768773 if let Some(tx) = vm_input_tx.lock().unwrap().clone() {
769− let _ = tx.send(VmInput::Bytes(b"systemctl poweroff\n".to_vec()));
774+ if tx
775+ .send(VmInput::Bytes(b"systemctl poweroff\n".to_vec()))
776+ .is_ok()
777+ {
778+ sent = true;
779+ } else {
780+ tracing::warn!("shutdown command failed to send");
781+ }
782+ } else {
783+ tracing::warn!("shutdown command deferred; vm input not ready");
770784 }
771− tracing::info!("shutdown command sent");
772− shutdown_sent = true;
773− shutdown_deadline = None;
785+ if sent {
786+ tracing::info!("shutdown command sent");
787+ shutdown_sent = true;
788+ shutdown_deadline = None;
789+ hard_deadline = Some(Instant::now() + hard_timeout);
790+ } else {
791+ shutdown_deadline = Some(Instant::now() + Duration::from_millis(500));
792+ }
793+ }
794+ if ref_count == 0
795+ && shutdown_sent
796+ && let Some(deadline) = hard_deadline
797+ && Instant::now() >= deadline
798+ {
799+ tracing::warn!(
800+ timeout_ms = HARD_SHUTDOWN_TIMEOUT_MS,
801+ "force exiting: VM did not stop after shutdown timeout"
802+ );
803+ std::process::exit(1);
774804 }
775805 }
776806 Err(mpsc::RecvTimeoutError::Disconnected) => break,