xref: /DragonOS/kernel/src/mm/percpu.rs (revision b5b571e02693d91eb6918d3b7561e088c3e7ee81)
1e2841179SLoGin use core::sync::atomic::AtomicU32;
2c3dad001SLoGin 
3c3dad001SLoGin use alloc::vec::Vec;
4c3dad001SLoGin 
5c3dad001SLoGin use crate::{
6338f6903SLoGin     libs::lazy_init::Lazy,
78cb2e9b3SLoGin     smp::{
88cb2e9b3SLoGin         core::smp_get_processor_id,
98cb2e9b3SLoGin         cpu::{smp_cpu_manager, ProcessorId},
108cb2e9b3SLoGin     },
11c3dad001SLoGin };
12c3dad001SLoGin 
13c3dad001SLoGin /// 系统中的CPU数量
14c3dad001SLoGin ///
15c3dad001SLoGin /// todo: 待smp模块重构后,从smp模块获取CPU数量。
16c3dad001SLoGin /// 目前由于smp模块初始化时机较晚,导致大部分内核模块无法在早期初始化PerCpu变量。
17*b5b571e0SLoGin static CPU_NUM_ATOMIC: AtomicU32 = AtomicU32::new(PerCpu::MAX_CPU_NUM);
18c3dad001SLoGin 
19c3dad001SLoGin #[derive(Debug)]
20c3dad001SLoGin pub struct PerCpu;
21c3dad001SLoGin 
22c3dad001SLoGin impl PerCpu {
2370f159a3SLoGin     #[cfg(target_arch = "x86_64")]
24e2841179SLoGin     pub const MAX_CPU_NUM: u32 = 128;
2570f159a3SLoGin     #[cfg(target_arch = "riscv64")]
2670f159a3SLoGin     pub const MAX_CPU_NUM: u32 = 64;
2770f159a3SLoGin 
28c3dad001SLoGin     /// # 初始化PerCpu
29c3dad001SLoGin     ///
30c3dad001SLoGin     /// 该函数应该在内核初始化时调用一次。
31c3dad001SLoGin     ///
32c3dad001SLoGin     /// 该函数会调用`smp_get_total_cpu()`获取CPU数量,然后将其存储在`CPU_NUM`中。
33c3dad001SLoGin     #[allow(dead_code)]
init()34c3dad001SLoGin     pub fn init() {
35*b5b571e0SLoGin         let cpu_num: &AtomicU32 = &CPU_NUM_ATOMIC;
36*b5b571e0SLoGin         if cpu_num.load(core::sync::atomic::Ordering::SeqCst) != 0 {
37c3dad001SLoGin             panic!("PerCpu::init() called twice");
38c3dad001SLoGin         }
398cb2e9b3SLoGin         let cpus = smp_cpu_manager().present_cpus_count();
408cb2e9b3SLoGin         assert!(cpus > 0, "PerCpu::init(): present_cpus_count() returned 0");
418cb2e9b3SLoGin 
42*b5b571e0SLoGin         CPU_NUM_ATOMIC.store(cpus, core::sync::atomic::Ordering::SeqCst);
43c3dad001SLoGin     }
44c3dad001SLoGin }
45c3dad001SLoGin 
46c3dad001SLoGin /// PerCpu变量
47c3dad001SLoGin ///
48c3dad001SLoGin /// 该结构体的每个实例都是线程安全的,因为每个CPU都有自己的变量。
49c3dad001SLoGin ///
50c3dad001SLoGin /// 一种简单的使用方法是:使用该结构体提供的`define_lazy`方法定义一个全局变量,
51c3dad001SLoGin /// 然后在内核初始化时调用`init`、`new`方法去初始化它。
52c3dad001SLoGin ///
53c3dad001SLoGin /// 当然,由于Lazy<T>有运行时开销,所以也可以直接全局声明一个Option,
54c3dad001SLoGin /// 然后手动初始化然后赋值到Option中。(这样需要在初始化的时候,手动确保并发安全)
55c3dad001SLoGin #[derive(Debug)]
56c3dad001SLoGin #[allow(dead_code)]
57c3dad001SLoGin pub struct PerCpuVar<T> {
58c3dad001SLoGin     inner: Vec<T>,
59c3dad001SLoGin }
60c3dad001SLoGin 
61c3dad001SLoGin #[allow(dead_code)]
62c3dad001SLoGin impl<T> PerCpuVar<T> {
63c3dad001SLoGin     /// # 初始化PerCpu变量
64c3dad001SLoGin     ///
65c3dad001SLoGin     /// ## 参数
66c3dad001SLoGin     ///
67c3dad001SLoGin     /// - `data` - 每个CPU的数据的初始值。 传入的Vec的长度必须等于CPU的数量,否则返回None。
new(data: Vec<T>) -> Option<Self>68c3dad001SLoGin     pub fn new(data: Vec<T>) -> Option<Self> {
69*b5b571e0SLoGin         let cpu_num = CPU_NUM_ATOMIC.load(core::sync::atomic::Ordering::SeqCst);
70c3dad001SLoGin         if cpu_num == 0 {
71c3dad001SLoGin             panic!("PerCpu::init() not called");
72c3dad001SLoGin         }
73c3dad001SLoGin 
74e2841179SLoGin         if data.len() != cpu_num.try_into().unwrap() {
75c3dad001SLoGin             return None;
76c3dad001SLoGin         }
77c3dad001SLoGin 
78c3dad001SLoGin         return Some(Self { inner: data });
79c3dad001SLoGin     }
80c3dad001SLoGin 
81c3dad001SLoGin     /// 定义一个Lazy的PerCpu变量,稍后再初始化
define_lazy() -> Lazy<Self>82c3dad001SLoGin     pub const fn define_lazy() -> Lazy<Self> {
83c3dad001SLoGin         Lazy::<Self>::new()
84c3dad001SLoGin     }
85c3dad001SLoGin 
get(&self) -> &T86c3dad001SLoGin     pub fn get(&self) -> &T {
87c3dad001SLoGin         let cpu_id = smp_get_processor_id();
88e2841179SLoGin         &self.inner[cpu_id.data() as usize]
89c3dad001SLoGin     }
90c3dad001SLoGin 
91*b5b571e0SLoGin     #[allow(clippy::mut_from_ref)]
get_mut(&self) -> &mut T928cb2e9b3SLoGin     pub fn get_mut(&self) -> &mut T {
93c3dad001SLoGin         let cpu_id = smp_get_processor_id();
948cb2e9b3SLoGin         unsafe {
958cb2e9b3SLoGin             &mut (self as *const Self as *mut Self).as_mut().unwrap().inner[cpu_id.data() as usize]
968cb2e9b3SLoGin         }
97c3dad001SLoGin     }
98338f6903SLoGin 
force_get(&self, cpu_id: ProcessorId) -> &T99338f6903SLoGin     pub unsafe fn force_get(&self, cpu_id: ProcessorId) -> &T {
100338f6903SLoGin         &self.inner[cpu_id.data() as usize]
101338f6903SLoGin     }
102338f6903SLoGin 
103*b5b571e0SLoGin     #[allow(clippy::mut_from_ref)]
force_get_mut(&self, cpu_id: ProcessorId) -> &mut T1048cb2e9b3SLoGin     pub unsafe fn force_get_mut(&self, cpu_id: ProcessorId) -> &mut T {
1058cb2e9b3SLoGin         &mut (self as *const Self as *mut Self).as_mut().unwrap().inner[cpu_id.data() as usize]
106338f6903SLoGin     }
107c3dad001SLoGin }
108c3dad001SLoGin 
109c3dad001SLoGin /// PerCpu变量是线程安全的,因为每个CPU都有自己的变量。
110c3dad001SLoGin unsafe impl<T> Sync for PerCpuVar<T> {}
111c3dad001SLoGin unsafe impl<T> Send for PerCpuVar<T> {}
112