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