pub enum PayloadKind {
Scheduler(&'static Scheduler),
Binary(&'static str),
}Expand description
How a payload is launched inside the guest.
Two variants — scheduler and binary — map to the two launch paths
in the runtime. “Kernel default” (EEVDF) is represented as
Scheduler(&Scheduler::EEVDF) rather than a dedicated variant
because Scheduler already carries the no-userspace-binary
taxonomy via its own binary: SchedulerSpec field.
Variants§
Scheduler(&'static Scheduler)
Wraps an existing Scheduler definition. The scheduler’s
own binary: SchedulerSpec carries the Eevdf/Discover/Path/
KernelBuiltin taxonomy — no duplication at the Payload level.
Binary(&'static str)
Bare userspace binary looked up by name in the guest. Not a scheduler — runs as a workload under whatever scheduler the test declares.
§How the binary reaches the guest
The stored &'static str is the executable name passed to
std::process::Command::new inside the guest (see
PayloadRun::run),
which resolves it against the guest’s PATH. The framework
resolves binaries through the include-file pipeline — for
#[ktstr_test] entries via declarative include_files /
extra_include_files, or via -i on ktstr shell.
Supply a binary through the framework’s include-file
pipeline. The pipeline is wired up to the shell subcommand
of both ktstr and cargo ktstr through the repeatable
-i / --include-files flag. Each -i argument accepts:
- an explicit path (absolute, relative, or containing
/) — must exist on the host; - a bare name — searched in
PATHon the host; - a directory — walked recursively, preserving structure under
/include-files/<dirname>/...in the guest.
Every regular file ends up at /include-files/<name> (or
deeper for directory walks). Dynamically-linked ELFs pull in
their DT_NEEDED shared libraries automatically; the guest
init prepends every /include-files/* subdirectory containing
an executable to PATH, so a binary packaged with -i is
runnable by bare name from a test body.
Example — launch a shell VM with fio available by bare name:
cargo ktstr shell -i fio --exec "fio --version"The fio binary is resolved against the host’s PATH, copied
to /include-files/fio in the guest, exposed on the guest
PATH, and spawnable as fio from any guest-side process.
§#[ktstr_test] entries
Declarative include_files on #[derive(Payload)] and
extra_include_files on #[ktstr_test] handle binary
packaging automatically — no CLI -i and no bespoke harness
needed.
§Scheduler config files
Scheduler-kind payloads that set
Scheduler’s config_file
field get automatic packaging: the config file is placed at
/include-files/{filename} without a -i flag — the field
is the source the harness reads.
§Binary-kind packaging
Payloads built via #[derive(Payload)] get automatic binary
packaging: the derive macro prepends the binary = "..."
spec to the emitted include_files slice, so the spawn
target is packaged into the guest without requiring a
separate #[include_files("...")] entry. Auxiliary files
the payload needs (helpers, config files, fixtures) still
go on #[include_files(...)] — the derive only injects the
primary binary.
Payloads constructed manually via struct literal (rather
than the derive) do not get this auto-injection: the
harness does not derive include_files from the
PayloadKind::Binary(name) at aggregation time. Manual
constructions must list the binary in
Payload::include_files
themselves, or declare it on
extra_include_files
at the #[ktstr_test] level. A binary referenced at spawn
time but neither auto-injected nor listed as an include is
expected to already be present in the guest filesystem
(e.g. a standard busybox applet on the base image);
otherwise the omission surfaces as ENOENT at exec time
inside the guest.
§Fork / kill semantics
A binary-kind payload is spawned in its own process group via
CommandExt::process_group(0) in
build_command so the
framework can reach every descendant the binary forks. Direct consequences for test
authors:
std::process::Child::kill()only targets the direct child — afork()ed descendant (stress-ng worker, fio--numjobs, schbench worker mode, pipeline subshells undersh -c) survives. Never callchild.kill()directly on a payloadChild; the handle’skill()wrapper fans out SIGKILL to the whole process group viakillpg.PayloadHandle::kill,PayloadHandle::waitcleanup, and the panic-safety Drop arm all route throughkill_payload_process_group, which issueskillpg(pgid, SIGKILL)followed by a single-pid SIGKILL fallback so descendants and the leader both exit. This is the only kill path test authors need.- Pipe drainers (stdout / stderr reader threads) block on EOF,
which only arrives after every descendant holding the
write ends closes them. A bare
child.kill()leaves the descendants holding the pipes open andwait_and_capturehangs forever — motivating thekillpgrequirement.
Trait Implementations§
Source§impl Clone for PayloadKind
impl Clone for PayloadKind
Source§fn clone(&self) -> PayloadKind
fn clone(&self) -> PayloadKind
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for PayloadKind
impl Debug for PayloadKind
impl Copy for PayloadKind
Auto Trait Implementations§
impl Freeze for PayloadKind
impl RefUnwindSafe for PayloadKind
impl Send for PayloadKind
impl Sync for PayloadKind
impl Unpin for PayloadKind
impl UnwindSafe for PayloadKind
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more