Repository navigation
nvx-rs: signal an execution's program without ending it, for graceful stops #858
Copy link
Copy link
Closed
Copy link
Description
Related: #620 (the host supervisor's graceful stop), #623 (the shared execution engine), #831 (adopted programs). Needs: nothing.
Goal. A guest caller can send an execution's program a signal other than SIGKILL through nvx::guest::exec, without ending the execution. The signal reaches the same targets as the execution's own kill, with the same protection against reused process IDs. A guest agent can then stop its workloads gracefully, as container runtimes do: SIGTERM, a grace period, then SIGKILL. It can also forward a signal that its host asks for, such as an interrupt or a hangup, through the library instead of through a process handle of its own.
Today (dev d04d9fb):
- An
Executionends its program only withSIGKILL, as its module documentation says (nvx-rs/src/guest/exec.rs:61-69).cancel,terminate,disconnectand the timeout (:883) all go throughend(:972) andsignal_program(:1011).- That sends
SIGKILLthrough the program's pidfd (sys::kill_through_pidfd,nvx-rs/src/guest/sys/process.rs:582-600, which hard-codes the signal at:594). - The kill reaches the program alone, or also the process group that the program leads (
Options::process_group,exec.rs:267). Before Linux 6.9, it signals the group by its ID while the program is unreaped (:1028). - It also kills the processes of the execution's cgroup (
Options::cgroup,:277).
- No call sends another signal. A caller that needs one brings its own handle to the program, and repeats the execution's targeting:
- When the execution collects the program's status, the program's pidfd shows only as a poll descriptor (
Source::Exit,exec.rs:314;descriptors,:815). - With
Options::caller_reaps(:297), as a PID 1 uses it, the execution exposes no pidfd at all. The caller opens or keeps one of its own, or signals by process ID, and must itself make sure that no collector has taken the program's status yet. - Either way, the caller repeats the process-group flag, the fallback before Linux 6.9, and the handling of
ESRCH.
- When the execution collects the program's status, the program's pidfd shows only as a poll descriptor (
- A caller that drives the execution through the engine's
Bindinggets only&Execution(nvx-rs/src/guest/exec/binding.rs:150). Every termination that the runner requests maps tocancel,disconnectorterminate(binding.rs:316-322), and so toSIGKILL. - The engine's grace (
Timers) lets pending output flow after the runner ends the workload (nvx-rs/src/exec/mod.rs:74-81). It doesn't give the workload time to handle a signal first. - On the host, the supervisor already stops a VMM gracefully, with a forced step that the caller chooses (nvx-rs: share the VMM supervisor and the sandbox store #620). The guest library's executions have no such step.
Scope (one PR):
Execution::signal(the name is open):- It sends a signal that the caller chooses through the program's pidfd. The signal reaches what the execution's kill reaches, except the cgroup: the program, and the process group that the program leads when
Options::process_groupis set. - It uses the same fallback before Linux 6.9. Once a collector has taken the program's status, it sends nothing, and tells the caller that the program is gone.
- It returns whether the program was unreaped, and reports a signal that the kernel refuses as an error.
- It doesn't end the execution: it records no
Cause, closes no input, and leaves the timeout in place. A program that exits after the signal ends with its own status, andOutcome::causereports no cause, as for a program that ended by itself. - Suggested: it refuses
SIGKILL, which stays withcancelandterminate, so that the outcome always says why the execution ended its program.
- It sends a signal that the caller chooses through the program's pidfd. The signal reaches what the execution's kill reaches, except the cgroup: the program, and the process group that the program leads when
- The same through
Binding, as a passthrough, since the binding exposes only&Execution. The runner sees nothing until the program exits. - Documentation: the module's "Status and ending" section describes a graceful stop:
signal, a wait until the caller's own deadline, thenterminateorcancel.
Acceptance:
- A program that handles
SIGTERMand exits with 0 ends with a successful status and no cause, and loses no output. - A program that ignores
SIGTERMkeeps running, andterminatethen ends it withCause::Terminated. - With
Options::process_group, a process of the group other than the program receives the signal. Before Linux 6.9, the fallback (exec.rs:1028) signals the group by its ID in the same way. - Once a collector has taken the program's status (
Options::caller_reapswithobserve),signalsends nothing and says that the program is gone, so it can't reach a process that later takes the same ID. - Both modes are covered: the execution collects the program's status, or the caller does. The same holds for an adopted program (nvx-rs: let an execution drive a program that its caller started #831) as for a spawned one.
- If the suggestion above is taken,
signalrefusesSIGKILL.
Not in this issue:
- A signal that the host requests through the execution engine (
nvx::exec) and an adapter's framing. A separate issue can follow if an adapter needs one. - Signals other than
SIGKILLto the processes of the execution's cgroup.cgroup.killsends onlySIGKILL, and signalling each process thatcgroup.procslists would race with forks. - Changes to how NVX's managed agent or the test adapter stop their executions.
Metadata
Metadata
Assignees
Labels
No labels
Activity