Skip to content

fix: graceful runtime shutdown, ECHILD race fix, and SendInput cleanup#270

Merged
DorianZheng merged 2 commits intomainfrom
fix/runtime-shutdown-and-echild
Feb 15, 2026
Merged

fix: graceful runtime shutdown, ECHILD race fix, and SendInput cleanup#270
DorianZheng merged 2 commits intomainfrom
fix/runtime-shutdown-and-echild

Conversation

@DorianZheng
Copy link
Copy Markdown
Member

Summary

  • Graceful runtime shutdown: shutdown_sync() for atexit/Drop, SIGTERM handler in shim, detached boxes survive, CLI shutdown path
  • ECHILD race fix: guest spawn_with_pipes() uses std::process::Command instead of Tokio (avoids SIGCHLD handler race with waitpid)
  • SendInput cleanup: spawn_stdin uses shutdown_token for clean cancellation during shutdown

Test plan

  • 20 unit tests pass (cargo test -p boxlite --lib rt_impl::tests)
  • 10 shutdown integration tests pass (cargo test -p boxlite --test shutdown)
  • 4 ECHILD/exec integration tests pass (cargo test -p boxlite --test execution_shutdown)
  • Clippy clean (cargo clippy -p boxlite --tests -- -D warnings)
  • Format clean (cargo fmt -p boxlite -- --check)
  • Manual: boxlite exec "box" -- ls / completes without WARN/ERROR logs
  • Manual: sequential boxlite exec runs succeed on same box

Three related fixes for clean process lifecycle management:

1. Runtime shutdown system: shutdown_sync() for atexit/Drop, SIGTERM
   handler in shim for graceful Guest.Shutdown RPC (qcow2 flush),
   detached boxes survive shutdown. CLI calls rt.shutdown() on exit.

2. Guest ECHILD fix: switch spawn_with_pipes() from tokio::process::Command
   to std::process::Command to avoid Tokio's orphan reaper racing with
   manual waitpid(). Added ECHILD safety net in wait_process().

3. Host SendInput fix: spawn_stdin now accepts shutdown_token and wraps
   send_input in tokio::select! for clean cancellation during shutdown.

Tests: 20 unit tests (shutdown_sync), 10 integration tests (shutdown),
4 integration tests (ECHILD/exec scenarios). All pass, clippy clean.
tokio's "full" meta-feature enables "process", which installs a global
SIGCHLD handler via signal_hook. This handler eagerly reaps children
with waitpid(-1, WNOHANG), racing with the guest's manual waitpid()
in wait_process() and causing ECHILD errors.

The guest never uses tokio::process — it uses std::process::Command
(GuestExecutor) and libcontainer (ContainerExecutor). Replace "full"
with only the features actually used: macros, rt-multi-thread, sync,
io-util, net, fs, time.
@DorianZheng DorianZheng merged commit f51697d into main Feb 15, 2026
14 checks passed
@DorianZheng DorianZheng deleted the fix/runtime-shutdown-and-echild branch February 15, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant