percpu.rs 3.2 KB

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