Firecracker shutdown on macOS

Jerboa requests a guest-visible VirtIO input KEY_POWER event when stopping a Nanos ELF guest under the macOS Firecracker/HVF backend. The Nanos driver re-arms all four event buffers before scheduling kernel_powerdown() outside interrupt context. Nanos then delivers SIGTERM to guest processes and runs its normal kernel shutdown path, including storage_sync(), before powering off.

The VMM waits up to 35 seconds for guest exit and then explicitly force-stops a non-cooperative guest. Jerboa keeps a separate 40-second outer process-kill bound so a broken control plane cannot leave the daemon’s stop request hanging. jerboa stop --force continues to terminate immediately.

These guarantees have an important boundary: kernel synchronization covers writes already handed to the kernel (including dirty page-cache data), not bytes still held only in an application’s userspace buffer. Applications that need their own transactional or protocol-level cleanup must handle SIGTERM and flush that state. A forced timeout is not a clean shutdown and must not be described as an fsync guarantee.

The reproducible macOS acceptance is:

python3 scripts/test-firecracker-shutdown.py

Override JERBOA_SHUTDOWN_FC to select another compatible Firecracker binary. The test creates an isolated temporary HOME, daemon sockets, dynamic ports, volumes and VMs. It covers a normally terminating application, an application that ignores SIGTERM for the full Nanos grace period, persistence after a new boot, immediate force-stop, restart suppression after explicit stop, and a kernel without the power driver that exercises the 35-second fallback.