1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Define and access per-CPU data structures.
//!
//! All per-CPU data is placed into several contiguous memory regions called
//! **per-CPU data areas**, the number of which is the number of CPUs. Each CPU
//! has its own per-CPU data area. The architecture-specific thread pointer
//! register (e.g., `GS_BASE` on x86_64) is set to the base address of the area
//! on initialization.
//!
//! When accessing the per-CPU data on the current CPU, it first use the thread
//! pointer register to obtain the corresponding per-CPU data area, and then add
//! an offset to access the corresponding field.
//!
//! # Notes
//!
//! Since RISC-V does not provide separate thread pointer registers for user and
//! kernel mode, we temporarily use the `gp` register to point to the per-CPU data
//! area, while the `tp` register is used for thread-local storage.
//!
//! # Examples
//!
//! ```no_run
//! #[percpu::def_percpu]
//! static CPU_ID: usize = 0;
//!
//! // initialize per-CPU data for 4 CPUs.
//! percpu::init(4);
//! // set the thread pointer register to the per-CPU data area 0.
//! percpu::set_local_thread_pointer(0);
//!
//! // access the per-CPU data `CPU_ID` on the current CPU.
//! println!("{}", CPU_ID.read_current()); // prints "0"
//! CPU_ID.write_current(1);
//! println!("{}", CPU_ID.read_current()); // prints "1"
//! ```
//!
//! # Cargo Features
//!
//! - `sp-naive`: For **single-core** use. In this case, each per-CPU data is
//!    just a global variable, architecture-specific thread pointer register is
//!    not used.
//! - `preempt`: For **preemptible** system use. In this case, we need to disable
//!    preemption when accessing per-CPU data. Otherwise, the data may be corrupted
//!    when it's being accessing and the current thread happens to be preempted.

#![cfg_attr(target_os = "none", no_std)]
#![feature(doc_cfg)]

extern crate percpu_macros;

#[cfg_attr(feature = "sp-naive", path = "naive.rs")]
mod imp;

pub use self::imp::*;
pub use percpu_macros::def_percpu;

#[doc(hidden)]
pub mod __priv {
    #[cfg(feature = "preempt")]
    pub use kernel_guard::NoPreempt as NoPreemptGuard;
}

cfg_if::cfg_if! {
    if #[cfg(doc)] {
        /// Example per-CPU data for documentation only.
        #[doc(cfg(doc))]
        #[def_percpu]
        pub static EXAMPLE_PERCPU_DATA: usize = 0;
    }
}