-
-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
97 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
use core::sync::atomic::AtomicUsize; | ||
|
||
use alloc::vec::Vec; | ||
|
||
use crate::{ | ||
include::bindings::bindings::smp_get_total_cpu, libs::lazy_init::Lazy, | ||
smp::core::smp_get_processor_id, | ||
}; | ||
|
||
/// 系统中的CPU数量 | ||
/// | ||
/// todo: 待smp模块重构后,从smp模块获取CPU数量。 | ||
/// 目前由于smp模块初始化时机较晚,导致大部分内核模块无法在早期初始化PerCpu变量。 | ||
const CPU_NUM: AtomicUsize = AtomicUsize::new(PerCpu::MAX_CPU_NUM); | ||
|
||
#[derive(Debug)] | ||
pub struct PerCpu; | ||
|
||
impl PerCpu { | ||
pub const MAX_CPU_NUM: usize = 128; | ||
/// # 初始化PerCpu | ||
/// | ||
/// 该函数应该在内核初始化时调用一次。 | ||
/// | ||
/// 该函数会调用`smp_get_total_cpu()`获取CPU数量,然后将其存储在`CPU_NUM`中。 | ||
#[allow(dead_code)] | ||
pub fn init() { | ||
if CPU_NUM.load(core::sync::atomic::Ordering::SeqCst) != 0 { | ||
panic!("PerCpu::init() called twice"); | ||
} | ||
let cpus = unsafe { smp_get_total_cpu() } as usize; | ||
assert!(cpus > 0, "PerCpu::init(): smp_get_total_cpu() returned 0"); | ||
CPU_NUM.store(cpus, core::sync::atomic::Ordering::SeqCst); | ||
} | ||
} | ||
|
||
/// PerCpu变量 | ||
/// | ||
/// 该结构体的每个实例都是线程安全的,因为每个CPU都有自己的变量。 | ||
/// | ||
/// 一种简单的使用方法是:使用该结构体提供的`define_lazy`方法定义一个全局变量, | ||
/// 然后在内核初始化时调用`init`、`new`方法去初始化它。 | ||
/// | ||
/// 当然,由于Lazy<T>有运行时开销,所以也可以直接全局声明一个Option, | ||
/// 然后手动初始化然后赋值到Option中。(这样需要在初始化的时候,手动确保并发安全) | ||
#[derive(Debug)] | ||
#[allow(dead_code)] | ||
pub struct PerCpuVar<T> { | ||
inner: Vec<T>, | ||
} | ||
|
||
#[allow(dead_code)] | ||
impl<T> PerCpuVar<T> { | ||
/// # 初始化PerCpu变量 | ||
/// | ||
/// ## 参数 | ||
/// | ||
/// - `data` - 每个CPU的数据的初始值。 传入的Vec的长度必须等于CPU的数量,否则返回None。 | ||
pub fn new(data: Vec<T>) -> Option<Self> { | ||
let cpu_num = CPU_NUM.load(core::sync::atomic::Ordering::SeqCst); | ||
if cpu_num == 0 { | ||
panic!("PerCpu::init() not called"); | ||
} | ||
|
||
if data.len() != cpu_num { | ||
return None; | ||
} | ||
|
||
return Some(Self { inner: data }); | ||
} | ||
|
||
/// 定义一个Lazy的PerCpu变量,稍后再初始化 | ||
pub const fn define_lazy() -> Lazy<Self> { | ||
Lazy::<Self>::new() | ||
} | ||
|
||
pub fn get(&self) -> &T { | ||
let cpu_id = smp_get_processor_id(); | ||
&self.inner[cpu_id as usize] | ||
} | ||
|
||
pub fn get_mut(&mut self) -> &mut T { | ||
let cpu_id = smp_get_processor_id(); | ||
&mut self.inner[cpu_id as usize] | ||
} | ||
} | ||
|
||
/// PerCpu变量是线程安全的,因为每个CPU都有自己的变量。 | ||
unsafe impl<T> Sync for PerCpuVar<T> {} | ||
unsafe impl<T> Send for PerCpuVar<T> {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters