添加per cpu变量支持 (#327)

This commit is contained in:
LoGin 2023-08-13 16:28:24 +08:00 committed by GitHub
parent 42c97fa7f4
commit c3dad0011d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 5 deletions

View File

@ -1,12 +1,13 @@
use core::arch::asm;
use super::asm::current::current_pcb;
use x86::cpuid::{cpuid, CpuIdResult};
/// @brief 获取当前cpu的apic id
#[inline]
pub fn current_cpu_id() -> u32 {
// TODO: apic重构后使用apic id来设置这里
current_pcb().cpu_id as u32
let cpuid_res: CpuIdResult = cpuid!(0x1);
let cpu_id = (cpuid_res.ebx >> 24) & 0xff;
return cpu_id;
}
/// @brief 通过pause指令让cpu休息一会儿。降低空转功耗

View File

@ -162,7 +162,7 @@ pub trait IndexNode: Any + Sync + Send + Debug {
}
/// @brief 重新设置文件的大小
///
///
/// 如果文件大小增加则文件内容不变但是文件的空洞部分会被填充为0
/// 如果文件大小减小,则文件内容会被截断
///

View File

@ -28,6 +28,7 @@ pub mod kernel_mapper;
pub mod mmio_buddy;
pub mod no_init;
pub mod page;
pub mod percpu;
pub mod syscall;
pub mod ucontext;

90
kernel/src/mm/percpu.rs Normal file
View File

@ -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> {}

View File

@ -78,7 +78,7 @@ impl Syscall {
if new_addr == address_space.brk {
return Ok(address_space.brk);
}
unsafe {
address_space
.set_brk(VirtAddr::new(page_align_up(new_addr.data())))