declare_scheduler!() { /* proc-macro */ }Expand description
Function-style macro that registers a Scheduler const.
§Syntax
use ktstr::prelude::*;
declare_scheduler!(MITOSIS, {
name = "mitosis",
binary = "scx_mitosis",
cgroup_parent = "/ktstr",
sched_args = ["--exit-dump-len", "1048576"],
kernels = ["6.14", "7.0..=7.2"],
constraints = TopologyConstraints {
min_llcs: 1, max_llcs: Some(8), max_cpus: Some(64),
..TopologyConstraints::DEFAULT
},
});§Generated items
Given declare_scheduler!(MITOSIS, { ... }):
pub static MITOSIS: ::ktstr::test_support::Scheduler— the declared scheduler value. No_PAYLOADsuffix; the const IS theScheduler.- A hidden
static __KTSTR_SCHED_REG_MITOSIS: &'static Schedulerregistered inKTSTR_SCHEDULERS(ktstr::test_support::KTSTR_SCHEDULERS) via linkme so the verifier can discover the declaration by spawning the test binary with--ktstr-list-schedulers.
§Visibility prefix
An optional Rust visibility prefix may precede the const name:
declare_scheduler!(MY_SCHED, { ... }); // defaults to `pub`
declare_scheduler!(pub MY_SCHED, { ... }); // explicit `pub`
declare_scheduler!(pub(crate) MY_SCHED, { ... }); // crate-local
declare_scheduler!(pub(super) MY_SCHED, { ... }); // parent-module
declare_scheduler!(pub(in crate::test_support) MY_SCHED, { ... });Omitting the prefix defaults to pub — schedulers are normally
public so the verifier and other crates can reference them; an
explicit prefix is needed only when the declaration sits inside
a module that wants to narrow the exposed name. (Field content
shown above as { ... } is elided; consult the Syntax example
for the required fields.) The hidden registry static (see
Generated items above) is always static (private) regardless
of the user-facing const’s visibility — linkme gathers it via
link-section walking, not Rust name resolution, so the slice
mechanism works at every visibility level.
§Accepted fields
Exactly one scheduler-source must be declared: binary,
binary_path, or the kernel_builtin_enable + kernel_builtin_disable
pair. The three options select between the matching
SchedulerSpec variants. To run under the kernel default
instead, reference ktstr::test_support::Scheduler::EEVDF
directly rather than declaring a new scheduler.
| Field | Required | Description |
|---|---|---|
name = "..." | yes | Scheduler name (sidecar / logs). |
binary = "..." | one source | Binary name → SchedulerSpec::Discover(...). Matched against [[bin]] names in target/{debug,release}/, the test binary’s directory, or KTSTR_SCHEDULER env var. Often equal to the cargo package name but not required to be. |
binary_path = "/abs/path" | one source | Absolute filesystem path → SchedulerSpec::Path(...). The runtime does not auto-build this variant: the file must already exist at the path when the test runs. Use for prebuilt binaries that live outside the cargo discovery cascade. Macro-time validation rejects empty strings, relative paths, and ~-prefixed paths (no compile-time tilde expansion); existence is the runtime’s job. |
kernel_builtin_enable = [..] + kernel_builtin_disable = [..] | one source | Two string-array literals that together select SchedulerSpec::KernelBuiltin { enable: &[..], disable: &[..] }. The framework writes the enable commands to the guest’s /sched_enable and the disable commands to /sched_disable (see src/vmm/initramfs.rs), and the guest interpreter runs each entry once at scenario start / teardown. Both fields must be set together — setting only one is rejected. The interpreter (src/vmm/rust_init/dump.rs) accepts EXACTLY ONE shell-line shape: echo VALUE > /path (plus blank lines and # comments). Pipes, >>, ;, variable expansion, and any other syntax silently no-ops at runtime, so the macro rejects entries that don’t match echo … > /… at expand time. At least one of the two arrays must be non-empty: a pair that supplies neither enable nor disable commands is equivalent to the EEVDF baseline — reference Scheduler::EEVDF for that. Note: cargo ktstr export currently bails on KernelBuiltin schedulers (src/export.rs); declarations using this variant cannot be reproduced via the export-to-shar workflow until that limitation is lifted. |
topology = (numa, llcs, cores, threads) | no | Default VM topology. Default: (1, 1, 2, 1) (from Scheduler::named). Validated at compile time: each value must be non-zero, and llcs must be a multiple of numa. |
cgroup_parent = "..." | no | Cgroup parent path (must begin with /). |
sched_args = [..] | no | Scheduler CLI args prepended before per-test extra_sched_args. |
sysctls = [Sysctl::new("k", "v"), ..] | no | Guest sysctls. |
kargs = [..] | no | Extra guest kernel cmdline args. |
kernels = ["6.14", "7.0..=7.2", ..] | no | Kernel specs the verifier sweeps. Same parser as the --kernel CLI flag — accepts exact versions, ranges (.. or ..=, both inclusive), git refs (git+URL#tag=NAME), paths, and cache keys. Each entry is validated at macro-expand time via the same KernelId::parse + validate the verifier uses at runtime; empty entries, inverted ranges, and ..-containing strings whose endpoints aren’t version-shaped (e.g. "abc..def") are rejected. |
constraints = TopologyConstraints { .. } | no | Gauntlet preset constraints — maps directly onto Scheduler::constraints. Filters which gauntlet topology presets exercise this scheduler. When given as a struct literal, the macro additionally cross-checks each literal field against the effective topology (explicit topology field if present, otherwise the (1, 1, 2, 1) default from Scheduler::named) and rejects infeasible pairings; non-struct-literal forms (e.g. OTHER::CONST_CONSTRAINTS) skip that check. |
assert = Assert::NO_OVERRIDES.method().chain() | no | Scheduler-wide assertion overrides — maps directly onto Scheduler::assert. Merged with Assert::default_checks() and the per-test assert at runtime (default ← scheduler ← per-test). Accepts any const-evaluable expression: a const path like Assert::NO_OVERRIDES, a const-fn call like Assert::default_checks(), or a chain of const-fn setters like Assert::NO_OVERRIDES.check_not_starved().max_gap_ms(50). The macro accepts MethodCall chains and Path-rooted (type/module-prefixed) Calls — only bare single-segment lowercase Calls like helper() are rejected as non-const free-fn patterns; non-const methods on a Path receiver slip through and surface as a deep const-eval failure at the spread site. |
config_file = "..." | no | Host-side config file path. |
config_file_def = ("--config {file}", "/include-files/cfg.json") | no | Inline-config plumbing — maps directly onto Scheduler::config_file_def. 2-tuple of string literals: arg_template (CLI arg with {file} placeholder substituted at run time) and guest_path (absolute path where the framework writes the JSON inside the guest). Distinct from config_file (which references a pre-existing host file). The macro validates: tuple-arity = 2, both elements non-empty string literals, {file} placeholder present in arg_template, guest_path absolute. |
§Const naming rules
The first argument must be a SCREAMING_SNAKE_CASE identifier and
must NOT be one of the reserved built-in names (EEVDF,
KERNEL_DEFAULT). The macro emits a compile_error! if either rule
is violated.