Skip to main content

Crate ax_percpu

Crate ax_percpu 

Source
Expand description

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

OperationRequired protection
Atomic scalarMigration disabled; local IRQs may remain enabled
Shared T: Sync objectMigration disabled; the object synchronizes itself
Local mutable objectMigration, IRQ/re-entry, and conflicting remote access excluded
Pre-pin CPU-owner objectMigration and context switches excluded; mutable access also excludes IRQ/re-entry and remote conflicts
Context switchIRQs and migration disabled; transactional tokens consumed
Preemption safe pointIRQs disabled; runtime baton claimed before pending release
vCPU runMigration disabled; exit assembly restores host registers before Rust
CPU-area initializationCPU 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.

Structs§

CpuAreaRef
Permanent typed reference to one fully initialized runtime CPU area.
CpuIndex
Dense logical index assigned to one CPU-local area.
CpuPin
Scoped proof that execution cannot migrate away from one validated CPU.
ExclusiveCpu
Scoped proof of exclusive local access to CPU-owned mutable state.
PerCpu
Typed descriptor for one symbol replicated in every runtime CPU area.
PerCpuArea
Descriptor for one initialized runtime per-CPU area.
PerCpuLayout
Frozen process-wide layout of initialized runtime per-CPU areas.
PerCpuRegion
Platform-owned raw storage geometry for runtime per-CPU areas.

Enums§

PerCpuError
Failure to initialize, locate, or access a runtime per-CPU area.

Statics§

EXAMPLE_PERCPU_DATAdoc
Example per-CPU data for documentation only.

Functions§

area
Returns one remote or current CPU area in O(1).
current_area
Verifies that pin selects the area installed for its logical CPU.
current_cpu_index
Returns the logical CPU index carried by a validated pin.
initialize_layout
Validates and constructs all values in raw runtime areas exactly once.
layout
Returns the immutable process-wide per-CPU layout.
with_cpu_pin
Runs operation with a validated, non-escaping CPU pin.
with_exclusive_cpu
Runs operation with exclusive access to mutable state on the pinned CPU.

Type Aliases§

EXAMPLE_PERCPU_DATA_WRAPPER
Wrapper type for the per-CPU data EXAMPLE_PERCPU_DATA

Attribute Macros§

def_percpu
Defines a per-CPU static variable.