From 9f9ba1fe3f8ebe999951cf64734481823a143f20 Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Fri, 8 May 2026 03:15:09 -0700 Subject: [PATCH] monitor: implement system_powerdown MMP command The QMP system_powerdown command shuts down the VM. machina has no separate ACPI shutdown path, so dispatch reuses the existing quit() path on MonitorService -- semantically equivalent for the embedded monitor and consistent with how the existing "quit" command reaches the shutdown signal. Add a regression test in tests/src/monitor.rs that mirrors the existing test_mmp_quit, asserting the empty success envelope and that is_quit_requested() flips to true after dispatch. Closes #88 Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> --- monitor/src/mmp.rs | 9 ++++++++- tests/src/monitor.rs | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/monitor/src/mmp.rs b/monitor/src/mmp.rs index c9b4be5f..26c0c909 100644 --- a/monitor/src/mmp.rs +++ b/monitor/src/mmp.rs @@ -101,7 +101,7 @@ fn handle_connection( if cmd == "qmp_capabilities" { caps_done = true; } - if cmd == "quit" { + if cmd == "quit" || cmd == "system_powerdown" { return true; } } @@ -130,6 +130,13 @@ pub fn dispatch(cmd: &str, svc: &Arc>) -> Value { s.quit(); json!({"return": {}}) } + "system_powerdown" => { + // QMP system_powerdown shuts down the VM. machina has no + // separate ACPI shutdown path, so reuse quit() which signals + // the run loop to stop -- semantically equivalent here. + s.quit(); + json!({"return": {}}) + } "query-cpus-fast" => { let cpus = s.query_cpus(); let arr: Vec = cpus diff --git a/tests/src/monitor.rs b/tests/src/monitor.rs index 67f25058..8dfae9a1 100644 --- a/tests/src/monitor.rs +++ b/tests/src/monitor.rs @@ -137,6 +137,17 @@ fn test_mmp_quit() { assert!(svc.lock().unwrap().state.is_quit_requested()); } +#[test] +fn test_mmp_system_powerdown() { + // QMP system_powerdown shuts down the VM. machina has no separate + // ACPI shutdown path, so dispatch must reuse quit() and return + // the empty success envelope. + let svc = make_svc(); + let resp = mmp::dispatch("system_powerdown", &svc); + assert_eq!(resp["return"], serde_json::json!({})); + assert!(svc.lock().unwrap().state.is_quit_requested()); +} + // ── HMP tests ─────────────────────────────────────── #[test]