CgroupDef

Struct CgroupDef 

Source
pub struct CgroupDef {
Show 15 fields pub name: Cow<'static, str>, pub cpuset: Option<CpusetSpec>, pub works: Vec<WorkSpec>, pub swappable: bool, pub payload: Option<&'static Payload>, pub cpuset_mems: Option<BTreeSet<usize>>, pub cpu: Option<CpuLimits>, pub memory: Option<MemoryLimits>, pub io: Option<IoLimits>, pub pids: Option<PidsLimits>, pub default_nice: Option<i32>, pub default_comm: Option<Cow<'static, str>>, pub default_uid: Option<u32>, pub default_gid: Option<u32>, pub default_numa_node: Option<u32>,
}
Expand description

Declarative cgroup definition: name + cpuset + synthetic WorkSpec groups + optional userspace Payload.

Bundles the ops that always go together (AddCgroup + SetCpuset + Spawn) into a single value. The executor creates the cgroup, optionally sets its cpuset, spawns workers for each WorkSpec entry, and moves them into the cgroup.

Multiple WorkSpec entries run in parallel within the cgroup. Each entry spawns its own set of worker processes. The optional Self::payload slot is a single userspace binary that runs alongside those synthetic WorkSpec groups (hence “plural works, singular payload” — the pluralization in the legacy “workload(s)” prose elided this distinction).

Use CgroupDef in Step::with_defs for scenarios where cgroups are created once and run for the step duration. Use Op::add_cgroup + Op::spawn(SpawnPlacement::cgroup(name), work) directly when you need mid-step cgroup creation, removal, or other dynamic operations between spawn and collect.

§Resource controllers overview

CgroupDef exposes one builder method per cgroup v2 controller knob, each writing the corresponding cgroup.* / *.max / *.weight file at apply_setup time. The full surface:

ControllerOne-line descriptionBuilder methodsUnderlying file(s)
cpusetBind to a CPU subset and NUMA-node memory affinity.Self::cpuset, Self::cpuset_memscpuset.cpus, cpuset.mems
cpuBandwidth ceiling (cpu.max quota/period) plus relative-share weight.Self::cpu_quota_pct, Self::cpu_quota, Self::cpu_unlimited, Self::cpu_weightcpu.max, cpu.weight
memoryHard ceiling, soft throttle threshold, soft protection floor, swap cap.Self::memory_max, Self::memory_high, Self::memory_low, Self::memory_swap_max, Self::memory_swap_unlimited, Self::memory_unlimitedmemory.max, memory.high, memory.low, memory.swap.max
ioRelative IO share (BFQ / io.cost) when the io controller is enabled.Self::io_weightio.weight
pidsTask-count ceiling — fork(2)/clone(2) returns EAGAIN once the cap is hit.Self::pids_max, Self::pids_unlimitedpids.max
freezePause/resume every task in the cgroup mid-run via the JOBCTL freeze path.(Op-level) Op::freeze_cgroup, Op::unfreeze_cgroupcgroup.freeze

CgroupDef covers steady-state resource limits — knobs that hold for the cgroup’s whole lifetime. The freeze knob is intentionally exposed at the Op layer instead, because freeze/unfreeze describe transitions over time (suspend mid-step, resume later) rather than the cgroup’s identity; see the “See also” section below for the full Op-variants list.

All builders are additive — a CgroupDef accumulates an optional CpuLimits / MemoryLimits / IoLimits / PidsLimits block. When a block is set (e.g. def.memory is Some), all knobs in that block are written — None-valued fields emit their kernel-default sentinel ("max" for memory.max/memory.high, "0" for memory.low). Only memory.swap.max is gated: None means no write (for CONFIG_SWAP=n compatibility). The “*_unlimited” builders explicitly rewind a knob to its sentinel value ("max" / "0") so a base CgroupDef factory can cap a resource and a per-test extension can clear that cap without rewriting the whole CgroupDef.

Validation runs at apply_setup time (before any worker spawn): out-of-range weights, cpu.max period == 0, and pids.max == Some(0) all produce actionable bails before the syscall fires. The kernel is the final authority on per-controller numeric ranges; framework-level checks catch only the foot-cannons documented per-builder.

§Builder semantics

The setters fall into three groups:

Group I — per-WorkSpec fan to works[0]: workers, workers_pct, work_type, sched_policy, affinity, mem_policy, mpol_flags. Each mutates self.works[0], auto-inserting a default WorkSpec when works is empty. There is NO cgroup-level default for these knobs — per-group identity (or per-group cpuset validation) makes fan-out semantically ambiguous. Use work + per-WorkSpec setters for multi-group cgroups.

Group II — cgroup-level default_* merge: nice, comm, uid, gid, numa_node. Each stores a value in a default_* field on CgroupDef. Every WorkSpec in works whose corresponding Option-typed field is None inherits the default at merged_works time — ORDER-INDEPENDENT with work. Some(_) (including Some(0)) opts out.

Group III — pcomm: mutates works in-place at call time, NOT order-independent — by design. See pcomm for the coalescing rationale.

Other setters (cpuset, cpuset_mems, the cpu_quota / memory_max / io_weight / pids_max controller families, workload, swappable) set cgroup-level state directly and do not participate in either merge pattern.

§See also

CgroupDef only expresses the steady-state shape of a cgroup (name, cpuset, work groups, payload). State changes that need to happen DURING a step — without tearing the cgroup down and recreating it — go through dedicated Op variants instead:

  • Op::FreezeCgroup / Op::UnfreezeCgroup — pause and resume every task in the cgroup via cgroup.freeze (the kernel-side asynchronous freeze path; not a SIGSTOP). Useful for scheduler suspend/resume tests that observe how the scheduler handles a workload that goes idle mid-step. Do not freeze a cgroup hosting the test’s own observers — see the deadlock warning on Op::FreezeCgroup.
  • Op::SetCpuset — re-pin an existing cgroup’s cpuset to exercise the scheduler’s response to a moving CPU mask without disrupting the worker tasks themselves.
  • Op::AddCgroup / Op::RemoveCgroup — add or destroy cgroups mid-step when a CgroupDef’s lifecycle is tied to step duration but the test wants a different (e.g. nested) cgroup to appear or disappear partway through.

These describe transitions over time rather than the cgroup’s identity, which is why they live as Op variants alongside the rest of the operation vocabulary rather than as CgroupDef builders.

// Single work group via convenience methods.
let def = CgroupDef::named("workers")
    .cpuset(CpusetSpec::disjoint(0, 2))
    .workers(4)
    .work_type(WorkType::SpinWait);

assert_eq!(def.name, "workers");
assert_eq!(def.works[0].num_workers, Some(4));

// Multiple concurrent work groups via .work().
let def = CgroupDef::named("mixed")
    .work(WorkSpec::default().workers(4).work_type(WorkType::SpinWait))
    .work(WorkSpec::default().workers(2).work_type(WorkType::YieldHeavy));

assert_eq!(def.works.len(), 2);

// Synthetic work + userspace binary side-by-side via .workload(&X).
// The binary runs inside the same cgroup as the WorkSpec handles;
// both spawn in apply_setup, the WorkSpec groups first, then the
// Payload after the cpuset settles.
let def = CgroupDef::named("io_and_spin")
    .cpuset(CpusetSpec::disjoint(0, 2))
    .workers(2)
    .work_type(WorkType::SpinWait)
    .workload(&BENCH);

assert!(def.payload.is_some());
assert_eq!(def.works[0].num_workers, Some(2));

Fields§

§name: Cow<'static, str>

Cgroup name relative to the scenario’s parent cgroup. Must be a valid cgroupfs filename.

§cpuset: Option<CpusetSpec>

Optional cpuset assignment. None inherits the parent cgroup’s cpuset (typically the scenario’s usable CPU set).

§works: Vec<WorkSpec>

WorkSpec groups to spawn. Empty means use a single default WorkSpec (SpinWait, Normal, ctx.workers_per_cgroup workers — defaults to 1 from CtxBuilder unless the scenario overrides it explicitly).

§swappable: bool

When true, the gauntlet work_type override replaces each WorkSpec’s work_type (applied per-WorkSpec via resolve_work_type).

§payload: Option<&'static Payload>

Optional userspace Payload to launch inside this cgroup.

Spawn order within apply_setup: the cgroup is created (add_cgroup_no_cpuset), its cpuset is resolved + set, then each WorkSpec entry is spawned and moved into the cgroup in declaration order, and finally — after every synthetic WorkSpec handle has started — the Payload is spawned via PayloadRun::new(ctx, p).in_cgroup(name).spawn(). This fixed order lets the cgroup cpuset and mempolicy settle on the WorkSpec handles before the binary inherits placement, so the binary sees a stable topology. Once spawned, all three (cgroup, works, payload) run concurrently until teardown.

Only PayloadKind::Binary payloads are accepted — scheduler-kind payloads are rejected at construction time via Self::workload. The payload is killed at step-teardown (before cgroup removal) so the cgroup removal does not fail with EBUSY.

§cpuset_mems: Option<BTreeSet<usize>>

Optional cpuset.mems NUMA node binding. None inherits the parent cgroup’s cpuset.mems. Set via Self::cpuset_mems.

§cpu: Option<CpuLimits>

Optional cpu controller limits (cpu.max, cpu.weight). None leaves both kernel defaults in place. Set via Self::cpu_quota_pct / Self::cpu_quota / Self::cpu_weight.

§memory: Option<MemoryLimits>

Optional memory controller limits (memory.max, memory.high, memory.low, memory.swap.max). None leaves all four at the kernel defaults. Set via Self::memory_max / Self::memory_high / Self::memory_low / Self::memory_swap_max.

§io: Option<IoLimits>

Optional io controller limits (io.weight). None leaves the kernel default in place. Set via Self::io_weight.

§pids: Option<PidsLimits>

Optional pids controller limits (pids.max). None leaves the kernel default in place (no ceiling). Set via Self::pids_max.

§default_nice: Option<i32>

Cgroup-level default for WorkSpec::nice. When Some(n), every WorkSpec in Self::works whose own nice field is None (the framework’s “skip setpriority(2)” state — see WorkloadConfig::nice) inherits Some(n) at apply-setup time. Set via Self::nice; merged in Self::merged_works.

Order-independent with Self::work: def.work(spec).nice(n) and def.nice(n).work(spec) produce identical effective WorkSpec values because the merge runs at merged_works() call time, not at builder-method call time.

§default_comm: Option<Cow<'static, str>>

Cgroup-level default for WorkSpec::comm. Merged into any WorkSpec whose own comm is None at apply-setup time. Set via Self::comm; merged in Self::merged_works.

§default_uid: Option<u32>

Cgroup-level default for WorkSpec::uid. Merged into any WorkSpec whose own uid is None at apply-setup time. Set via Self::uid; merged in Self::merged_works.

§default_gid: Option<u32>

Cgroup-level default for WorkSpec::gid. Merged into any WorkSpec whose own gid is None at apply-setup time. Set via Self::gid; merged in Self::merged_works.

§default_numa_node: Option<u32>

Cgroup-level default for WorkSpec::numa_node. Merged into any WorkSpec whose own numa_node is None at apply-setup time. Set via Self::numa_node; merged in Self::merged_works.

Implementations§

Source§

impl CgroupDef

Source

pub fn named(name: impl Into<Cow<'static, str>>) -> Self

Create a CgroupDef with defaults (empty works, no cpuset).

apply_setup fills an empty works slice with one default WorkSpec (SpinWait, SCHED_NORMAL, ctx.workers_per_cgroup workers — defaults to 1 from CtxBuilder). For an empty move-target cgroup with no workers, declare it via Op::AddCgroup at step or Backdrop level. For the common CgroupDef::named(name).workers(ctx.workers_per_cgroup) pattern use Ctx::cgroup_def.

Source

pub fn cpuset(self, cpus: CpusetSpec) -> Self

Set Self::cpuset; see Op::SetCpuset for mid-run changes.

Source

pub fn work(self, w: WorkSpec) -> Self

Append a WorkSpec group (multiple calls yield concurrent groups within this cgroup).

Source

pub fn workers(self, n: usize) -> Self

Set WorkSpec::num_workers on works[0] (Group I).

n MUST be >= 1. n == 0 is rejected at apply-setup time by resolve_num_workers (before any worker spawn) with an actionable diagnostic naming the cgroup; WorkloadConfig::validate is the downstream defense-in-depth gate. A zero-worker spawn would silently produce no workload load, vacuously passing scheduler assertions that rely on observable contention. Pass n >= 1; for fraction-of-cpuset sizing use Self::workers_pct.

Source

pub fn workers_pct(self, pct: f64) -> Self

Set WorkSpec::workers_pct on works[0] (Group I). Resolved against the cgroup’s cpuset at apply-setup via ceil(cpuset_cpus * pct). Mutually exclusive with Self::workers — see WorkSpec::workers_pct.

§Panics

Panics when pct is NaN, infinite, or <= 0.0. Extreme finite values (e.g. 1e100) pass the gate and saturate to usize::MAX via the as cast in resolve_workers_pct (RFC 2484 / Rust 1.45+) — attempting to spawn that many workers would OOM the host. Keep pct near the intended oversubscription factor (e.g. 1.0, 2.0, 4.0).

Source

pub fn work_type(self, wt: WorkType) -> Self

Set WorkSpec::work_type on works[0] (Group I).

Source

pub fn sched_policy(self, p: SchedPolicy) -> Self

Set WorkSpec::sched_policy on works[0] (Group I).

Source

pub fn affinity(self, a: AffinityIntent) -> Self

Set WorkSpec::affinity on works[0] (Group I).

Source

pub fn mem_policy(self, p: MemPolicy) -> Self

Set WorkSpec::mem_policy on works[0] (Group I). Validated against the resolved cpuset per-group.

Source

pub fn mpol_flags(self, f: MpolFlags) -> Self

Set WorkSpec::mpol_flags on works[0] (Group I).

Source

pub const fn nice(self, n: i32) -> Self

Set Self::default_nice (Group II). Note: WorkSpec::nice(0) stores Some(0) and opts out of this default — the worker’s nice is explicitly set to 0 via setpriority(2) rather than inheriting.

Source

pub fn comm(self, name: impl Into<Cow<'static, str>>) -> Self

Set Self::default_comm (Group II).

§Panics

Panics on programmer-error inputs — mirrors crate::workload::WorkSpec::pcomm’s # Panics:

  • Empty string.
  • Interior NUL byte.
  • More than 15 bytes (TASK_COMM_LEN - 1 cap).

See validate_task_comm_string (in crate::workload) for the centralized rationale; name.len() is the BYTE length (UTF-8 multi-byte chars count as their byte width).

Source

pub const fn uid(self, uid: u32) -> Self

Set Self::default_uid (Group II).

Source

pub const fn gid(self, gid: u32) -> Self

Set Self::default_gid (Group II).

Source

pub fn pcomm(self, name: impl Into<Cow<'static, str>>) -> Self

Set the thread-group leader’s comm on every WorkSpec in this CgroupDef. Each affected WorkSpec gets pcomm = Some(name); existing per-WorkSpec pcomm values (set before this call) are overwritten. Calling on an empty works list pushes a default WorkSpec carrying the value.

The pcomm string is applied via prctl(PR_SET_NAME) on the forked thread-group leader. The builder rejects > 15 bytes (TASK_COMM_LEN-1) at construction so the task->group_leader->comm == pcomm invariant the framework relies on holds exactly. Setting this triggers the fork-then-thread spawn path in apply_setup: WorkSpecs sharing a pcomm value coalesce into ONE thread-group leader per group; every worker thread inside observes task->group_leader->comm == pcomm. Each worker thread additionally sets its own task->comm via .comm() on the per-WorkSpec WorkSpec::comm at thread creation time.

pcomm lives ONLY on WorkSpec — there is no CgroupDef-level field. This builder writes the value into every WorkSpec directly so apply_setup has a single authoritative source per WorkSpec.

Not order-independent with Self::work — by design. Unlike Group II setters, pcomm mutates works in-place when called: it stamps every WorkSpec that EXISTS at call time and then returns. WorkSpecs added via subsequent Self::work calls are not retroactively touched, and a WorkSpec that already carried its own pcomm is OVERWRITTEN if it was pushed before .pcomm(..) ran. This is intentional — pcomm determines the thread-group leader’s coalescing key in apply_setup, so the framework needs the value baked onto each WorkSpec by the time merged_works() runs. Storing it as a default and merging at read time would break the coalescing contract for the empty-works case (the synthesised WorkSpec::default() would have to carry the pcomm without distinguishing “default” from “explicit override”).

§Panics

Panics on programmer-error inputs — mirrors crate::workload::WorkSpec::pcomm’s # Panics:

  • Empty string.
  • Interior NUL byte.
  • More than 15 bytes (TASK_COMM_LEN - 1 cap).

See validate_task_comm_string (in crate::workload) for the centralized rationale; name.len() is the BYTE length (UTF-8 multi-byte chars count as their byte width).

Source

pub const fn numa_node(self, node: u32) -> Self

Set Self::default_numa_node (Group II).

Source

pub const fn swappable(self, swappable: bool) -> Self

Set Self::swappable (gauntlet work_type override).

Source

pub fn workload(self, p: &'static Payload) -> Self

Attach a userspace payload binary that runs inside this cgroup alongside any synthetic WorkSpec groups. The payload spawns when the step enters apply_setup and is killed during step-teardown so the cgroup can be removed cleanly.

§Panics

Panics when p.is_scheduler() (i.e. p is a scheduler-kind PayloadKERNEL_DEFAULT or any other PayloadKind::Scheduler* variant). Only PayloadKind::Binary payloads are accepted; CgroupDef.workload is for userspace binary payloads only, and scheduler placement uses #[ktstr_test(scheduler = ...)] instead.

Why panic at declaration time, not at spawn time? Three reasons, all of which favor failing fast:

  1. Discovery-time surfacing. CgroupDef builders run during test construction, which nextest’s --list invocation reaches BEFORE any VM boot. A panic here emits a full backtrace inside the test binary and surfaces the offending call site immediately; a deferred runtime error would require a KVM-capable host + a kernel image + an initramfs build to observe — a 30+ second feedback loop for what is purely a typed-API misuse.
  2. No side effects. The panic happens before CgroupDef.payload = Some(p) assignment runs, so the in-progress builder is left in its prior (no-payload) state. A caller that catches the panic via catch_unwind sees a valid CgroupDef either way.
  3. Scheduler-kind is always a programming error here. Payload::KERNEL_DEFAULT in CgroupDef::workload is never a legitimate use case — it means the author confused the scheduler slot (test-level) with the workload slot (cgroup-level). There is no recovery path; the only resolution is editing the source.

Scheduler-kind payloads in the step-level Op::RunPayload path bail with an anyhow::Error instead of panicking — that path runs during scenario execution where one bad op should not crash a whole test run.

Source

pub fn cpuset_mems(self, nodes: BTreeSet<usize>) -> Self

Bind cpuset.mems for this cgroup. Mirrors Self::cpuset for NUMA memory placement: the cgroup’s tasks may only allocate memory on the listed NUMA nodes. None (default) inherits the parent’s cpuset.mems.

Required when the cgroup spans CPUs on a NUMA node whose memory is NOT in the parent’s cpuset.mems — allocations from the cgroup’s tasks are constrained to the parent’s allowed nodes per kernel/cgroup/cpuset.c. The framework writes cpuset.mems immediately after cpuset.cpus so the binding is in effect before any worker is moved in.

Source

pub fn cpu_quota_pct(self, pct: u32) -> Self

Set cpu.max quota as a percentage of one CPU’s throughput, with a default 100 ms period. 100 means “one full CPU” (quota=100_000, period=100_000); 200 means “two CPUs”. Use Self::cpu_quota for non-default periods.

Source

pub fn cpu_quota(self, quota: Duration, period: Duration) -> Self

Set cpu.max quota and period directly. quota may exceed period (multi-CPU concurrency, see CpuLimits::max_quota_us). Both arguments are converted to microseconds; sub-microsecond fractions in the supplied Durations are truncated.

Source

pub fn cpu_unlimited(self) -> Self

Clear any previously-set cpu.max quota (writes "max"), leaving cpu.weight (if set) intact. Useful when a base CgroupDef builder applied a default cap and the test wants only weight-based bias.

Source

pub fn cpu_weight(self, weight: u32) -> Self

Set cpu.weight (CGROUP_WEIGHT_MIN..=CGROUP_WEIGHT_MAX, 1..=10000; CGROUP_WEIGHT_DFL = 100; enforced by cpu_weight_write_u64 in kernel/sched/core.c). Larger values get a larger share under contention. Independent of cpu.max.

Source

pub fn memory_max(self, bytes: u64) -> Self

Set memory.max hard ceiling in bytes. Crossing this triggers reclaim first (try_charge_memcg in mm/memcontrol.c); the cgroup OOM killer fires only after MAX_RECLAIM_RETRIES failed retries, and is skipped when the allocation carries __GFP_NORETRY or __GFP_RETRY_MAYFAIL.

Source

pub fn memory_high(self, bytes: u64) -> Self

Set memory.high soft throttle threshold in bytes. Crossing this triggers reclaim throttling but NOT OOM-kill — per __mem_cgroup_handle_over_high in mm/memcontrol.c: “memory.high enforcement isn’t as strict, and there is no OOM killer involved”.

Source

pub fn memory_low(self, bytes: u64) -> Self

Set memory.low soft protection threshold in bytes. Reclaim prefers other cgroups before this one’s memory drops below low.

Source

pub fn memory_unlimited(self) -> Self

Clear all three memory limits (writes "max" for max/high and "0" for low). Equivalent to leaving memory unset at construction; provided for symmetry with Self::cpu_unlimited.

Source

pub fn io_weight(self, weight: u16) -> Self

Set io.weight (CGROUP_WEIGHT_MIN..=CGROUP_WEIGHT_MAX, 1..=10000; CGROUP_WEIGHT_DFL = 100; enforced by ioc_weight_write in block/blk-iocost.c). Biases relative IO share when the io controller is enabled. io.max per-device caps are not surfaced — see IoLimits.

Source

pub fn memory_swap_max(self, bytes: u64) -> Self

Set memory.swap.max ceiling in bytes. The kernel parses the wire value via page_counter_memparse and accepts a decimal byte count (swap_max_write in mm/memcontrol.c). Distinct from memory.max: this caps how much of the cgroup’s memory can spill to swap, separate from total memory consumption.

Source

pub fn memory_swap_unlimited(self) -> Self

Clear any previously-set memory.swap.max (writes "max"). Mirrors Self::cpu_unlimited / Self::memory_unlimited for a single memory-knob unset; useful when a base CgroupDef builder applied a swap cap and the test wants to remove only that knob while preserving memory.max/high/ low.

No-ops when self.memory == None — the default state already means “no swap cap” (apply_setup emits no memory writes for an unset memory field), so creating a fresh MemoryLimits just to set swap_max = None would (a) be redundant and (b) trigger 3 unwanted writes for memory.max / memory.high / memory.low at apply_setup time. The no-op short-circuit keeps “fresh CgroupDef + memory_swap_unlimited()” semantically identical to “fresh CgroupDef”.

Source

pub fn pids_max(self, n: u64) -> Self

Set pids.max task-count ceiling. n is the maximum number of processes the cgroup may host before subsequent fork() / clone() calls return EAGAIN. Existing tasks are NOT killed when the limit lands below the current count (per the pids_max_write kernel comment: “Limit updates don’t need to be mutex’d, since it isn’t critical that any racing fork()s follow the new limit”).

n = 0 is rejected at apply_setup time: a 0-limit cgroup halts every fork/clone inside, including the worker spawn under CloneMode::Fork and the ForkExit per-iteration child fork. There is no kernel sentinel for “no fork ever”; pids_max=0 silently fails every fork() inside with EAGAIN, which is almost certainly a configuration bug.

Source

pub fn pids_unlimited(self) -> Self

Clear any previously-set pids.max (writes "max"). Mirrors Self::cpu_unlimited / Self::memory_unlimited.

Source

pub fn merged_works(&self) -> Vec<WorkSpec>

Materialize Self::works with cgroup-level defaults merged into each entry. Called by apply_setup to resolve the per-WorkSpec values before spawning workers.

For every WorkSpec in Self::works (or a single WorkSpec::default() when works is empty, matching apply_setup’s default-substitution rule), each cgroup-level default in Self::default_nice / Self::default_comm / Self::default_uid / Self::default_gid / Self::default_numa_node fills the corresponding WorkSpec field when that field is “unset” at the WorkSpec level.

“Unset” means None for every Option-typed field — nice, comm, uid, gid, numa_node are all Option<_>. The framework’s “skip setpriority(2)” state per WorkloadConfig::nice is None. A WorkSpec that explicitly sets Some(n) (including Some(0)) keeps its value; the cgroup-level default applies only when the WorkSpec is at the framework default of None.

pcomm is NOT propagated through merged_works. The Self::pcomm convenience method writes pcomm directly into every WorkSpec at builder time so coalescing in apply_setup reads the per-WorkSpec value (the authoritative source).

Decoupling this merge from the convenience-method call sites makes the builder order-independent — def.nice(5).work(spec) and def.work(spec).nice(5) produce identical effective WorkSpec values.

Trait Implementations§

Source§

impl Clone for CgroupDef

Source§

fn clone(&self) -> CgroupDef

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CgroupDef

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl FromIterator<CgroupDef> for Backdrop

Backdrop::from_iter(cgroups) / cgroups.into_iter().collect() shortcuts for the common “build a Backdrop from a Vec of cgroup defs” pattern test fixtures repeat. Equivalent to Backdrop::from_cgroups; declaration order is preserved.

Source§

fn from_iter<I: IntoIterator<Item = CgroupDef>>(defs: I) -> Self

Creates a value from an iterator. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> MaybeSend for T
where T: Send,

§

impl<T> MaybeSend for T
where T: Send,