Getting Started

Relevant source files

This page provides a step-by-step guide to integrating and using the percpu crate for per-CPU data management in your projects. It covers the essential workflow from dependency setup through basic usage patterns, serving as an entry point for developers new to the percpu system.

For detailed installation instructions and build environment configuration, see Installation and Setup. For comprehensive examples and advanced usage patterns, see Basic Usage Examples. For information about configuring features for different deployment scenarios, see Feature Flags Configuration.

Integration Workflow Overview

The percpu crate requires coordination between compile-time code generation, linker script configuration, and runtime initialization. The following diagram illustrates the complete integration workflow:

flowchart TD
subgraph subGraph2["Generated Artifacts"]
    SECTION[".percpu sectionin binary"]
    WRAPPER["Generated wrapper structswith access methods"]
    AREAS["Per-CPU memory areasat runtime"]
end
subgraph subGraph1["Code Development"]
    DEFINE["Define per-CPU variables#[percpu::def_percpu]"]
    INIT["Initialize systempercpu::init()"]
    SETUP["Configure per-CPU registerspercpu::init_percpu_reg()"]
    ACCESS["Access variablesread_current(), write_current()"]
end
subgraph subGraph0["Build Configuration"]
    CARGO["Add percpu dependencyto Cargo.toml"]
    FEATURES["Configure feature flagssp-naive, preempt, arm-el2"]
    LINKER["Modify linker scriptAdd .percpu section"]
end
START["Start Integration"]

AREAS --> ACCESS
CARGO --> FEATURES
DEFINE --> SECTION
DEFINE --> WRAPPER
FEATURES --> LINKER
INIT --> AREAS
LINKER --> DEFINE
SECTION --> AREAS
SETUP --> ACCESS
START --> CARGO
WRAPPER --> ACCESS

Sources: README.md(L39 - L52)  percpu/tests/test_percpu.rs(L35 - L50) 

Essential Components and Their Relationships

The percpu system consists of several key components that work together to provide efficient per-CPU data access. Understanding these relationships is crucial for proper integration:

flowchart TD
subgraph subGraph3["Linker Script Space"]
    SCRIPT["_percpu_start_percpu_end_percpu_load_start"]
    SECTION[".percpu 0x0 (NOLOAD)section definition"]
end
subgraph subGraph2["Runtime System Space"]
    AREAS["percpu_area_base()memory allocation"]
    REGISTER["read_percpu_reg()write_percpu_reg()"]
    OFFSETS["CPU_ID.offset()address calculation"]
end
subgraph subGraph1["Generated Code Space"]
    STORAGE["__PERCPU_CPU_IDin .percpu section"]
    WRAPPER["CPU_ID_WRAPPERaccess methods"]
    INTERFACE["CPU_ID: CPU_ID_WRAPPERpublic interface"]
end
subgraph subGraph0["User Code Space"]
    USRVAR["#[percpu::def_percpu]static CPU_ID: usize = 0"]
    USRINIT["percpu::init()"]
    USRSETUP["percpu::init_percpu_reg(0)"]
    USRACCESS["CPU_ID.read_current()"]
end

AREAS --> SCRIPT
INTERFACE --> USRACCESS
SCRIPT --> SECTION
STORAGE --> SCRIPT
USRACCESS --> OFFSETS
USRACCESS --> REGISTER
USRINIT --> AREAS
USRSETUP --> REGISTER
USRVAR --> STORAGE
USRVAR --> WRAPPER
WRAPPER --> INTERFACE

Sources: README.md(L40 - L51)  percpu/tests/test_percpu.rs(L7 - L31)  percpu/test_percpu.x(L6 - L14) 

Quick Start Example

The following table summarizes the minimal steps required to integrate percpu into a project:

StepActionCode ExamplePurpose
1Add dependencypercpu = "0.1"in Cargo.tomlEnable percpu macros and runtime
2Configure linkerAdd.percpusection to linker scriptReserve memory for per-CPU data
3Define variables#[percpu::def_percpu] static VAR: Type = init;Declare per-CPU storage
4Initialize systempercpu::init();Allocate per-CPU memory areas
5Setup registerspercpu::init_percpu_reg(cpu_id);Configure architecture registers
6Access dataVAR.read_current(),VAR.write_current(value)Use per-CPU variables

Here's a complete minimal example demonstrating the basic workflow:

// In your source code
#[percpu::def_percpu]
static CPU_COUNTER: usize = 0;

fn main() {
    // Initialize the per-CPU system
    percpu::init();
    
    // Configure per-CPU register for CPU 0
    percpu::init_percpu_reg(0);
    
    // Access per-CPU data
    println!("Initial value: {}", CPU_COUNTER.read_current()); // prints "0"
    CPU_COUNTER.write_current(42);
    println!("Updated value: {}", CPU_COUNTER.read_current()); // prints "42"
}

And the corresponding linker script addition:

. = ALIGN(4K);
_percpu_start = .;
_percpu_end = _percpu_start + SIZEOF(.percpu);
.percpu 0x0 (NOLOAD) : AT(_percpu_start) {
    _percpu_load_start = .;
    *(.percpu .percpu.*)
    _percpu_load_end = .;
    . = _percpu_load_start + ALIGN(64) * CPU_NUM;
}
. = _percpu_end;

Sources: README.md(L39 - L51)  README.md(L54 - L67)  percpu/test_percpu.x(L1 - L16) 

Architecture-Specific Considerations

The percpu system supports multiple architectures with different per-CPU register mechanisms. The following table shows the supported platforms and their register usage:

ArchitecturePer-CPU RegisterUsage Notes
x86_64GS_BASEStandard x86_64 per-CPU mechanism
AArch64TPIDR_EL1/TPIDR_EL2EL1 by default, EL2 witharm-el2feature
RISC-VgpGlobal pointer register (non-standard usage)
LoongArch$r21Architecture-specific register

The system automatically generates appropriate assembly code for each architecture during macro expansion. No manual architecture-specific code is required in user applications.

Sources: README.md(L19 - L35) 

Feature Configuration Overview

The percpu crate provides several feature flags to adapt to different deployment scenarios:

  • sp-naive: Single-processor mode using global variables instead of per-CPU mechanisms
  • preempt: Preemption-safe mode with automatic guard integration
  • arm-el2: Hypervisor mode support for AArch64 using EL2 registers

Choose features based on your target environment. For single-core systems, use sp-naive. For preemptible kernels, enable preempt. For ARM hypervisors, add arm-el2.

Sources: README.md(L69 - L79) 

Next Steps

After completing the basic integration:

  1. Detailed Setup: See Installation and Setup for comprehensive dependency management, build configuration, and linker script integration
  2. Advanced Usage: See Basic Usage Examples for complex data types, remote CPU access, and safety patterns
  3. Feature Configuration: See Feature Flags Configuration for choosing appropriate features for your deployment scenario
  4. Architecture Details: See Cross-Platform Abstraction for understanding platform-specific implementation details
  5. Safety Guidelines: See Safety and Preemption for proper usage patterns and avoiding common pitfalls

Sources: README.md percpu/tests/test_percpu.rs