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