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