ax-percpu 0.4.18

Define and access per-CPU data structures
Documentation

ax-percpu

Typed per-CPU layout, initialization, and access for no_std kernels.

ax-percpu is dynamic-only. The final ELF contains one layout template; the platform allocates one writable runtime area per CPU and initializes the complete layout before any CPU is bound. Architecture register ownership is provided by the separate cpu-local crate.

Runtime contract

The initialization sequence is fixed:

  1. The linker retains exactly one .percpu.template plus the .percpu.init and .percpu.align descriptor tables.
  2. The platform allocates shutdown-lifetime storage for every CPU area.
  3. initialize_layout(PerCpuRegion) validates the complete geometry and descriptor tables before the first destination write.
  4. Each CpuAreaPrefix and each typed value is constructed once at its final runtime address.
  5. The layout is frozen; the platform may then install area(cpu).cpu_area() through its offline-CPU boundary.

There is no linked runtime layout or static per-CPU replication. Changing the runtime CPU count therefore does not change the ELF template size.

The linker contract uses only these output sections:

  • .percpu.template
  • .percpu.init
  • .percpu.align

Generated storage is placed in .percpu.template.storage; the fixed prefix and end sentinel use .percpu.template.header and .percpu.template.end. Linker boundaries use __PERCPU_* and __CPU_LOCAL_* names.

Typed access

#[ax_percpu::def_percpu]
static CPU_ID: usize = 0;

fn set_cpu_id(pin: &ax_percpu::CpuPin<'_>, cpu_id: usize) {
    ax_percpu::current_area(pin).expect("CPU area must match the frozen layout");
    CPU_ID.write_current(pin, cpu_id);
    assert_eq!(CPU_ID.read_current(pin), cpu_id);
}

Primitive values use the matching atomic storage type. Object initializers are retained as typed descriptor thunks and construct one independent value in each final runtime area; arbitrary Rust object bytes are never duplicated from the ELF template.

Current access requires a scoped CpuPin, which validates the live register, area self pointer, and CPU index when it is created. A mutable object borrow additionally requires ExclusiveCpu; only the unsafe guard integration can create that stronger capability after excluding IRQ/re-entry and conflicting remote access.

Low-level execution-context owners and offline-bootstrap code can use the hidden with_current_cpu_area and with_current_cpu_area_mut callbacks before a CpuPin exists. These callbacks select the architecture-owned CPU area directly instead of routing CPU-owned state through current execution-context publication. The caller retains the complete migration, context-switch, IRQ/re-entry, and remote aliasing contract. No runtime path uses these callbacks yet; they are reserved for future owner-guard and offline CPU bootstrap integration.

Operation Required protection
Atomic scalar Migration disabled; local IRQs may remain enabled
Shared T: Sync object Migration disabled; the object synchronizes itself
Local mutable object Migration, IRQ/re-entry, and conflicting remote access excluded
Pre-pin CPU-owner object Migration and context switches excluded; mutable access also excludes IRQ/re-entry and remote conflicts
Context switch IRQs and migration disabled; transactional tokens consumed
Preemption safe point IRQs disabled; runtime baton claimed before pending release
vCPU run Migration disabled; exit assembly restores host registers before Rust
CPU-area initialization CPU offline and raw area exclusively owned

Host tests

The crate exposes one feature, host-test. It provides:

let layout = ax_percpu::host_test::initialize(
    core::num::NonZeroU32::new(4).unwrap(),
)?;
let area = ax_percpu::area(ax_percpu::CpuIndex::try_from(0)?)?;
unsafe { cpu_local::install_cpu_area(area.cpu_area()?)? };
unsafe {
    ax_percpu::with_cpu_pin(|pin| {
        assert_eq!(ax_percpu::current_area(pin), Ok(area));
    })?;
}

The helper owns process-lifetime dynamic storage and initializes it once. Each modeled CPU thread must explicitly install its own binding.

Validation

cargo test -p ax-percpu --features host-test
cargo test -p ax-percpu-macros
cargo xtask clippy --package ax-percpu

Licensed under Apache-2.0.