Files
DragonOS/kernel/src/sched/rt.rs
LoGin d8ad0a5e77 新的内存管理模块 (#301)
  实现了具有优秀架构设计的新的内存管理模块,对内核空间和用户空间的内存映射、分配、释放、管理等操作进行了封装,使得内核开发者可以更加方便地进行内存管理。

  内存管理模块主要由以下类型的组件组成:

- **硬件抽象层(MemoryManagementArch)** - 提供对具体处理器架构的抽象,使得内存管理模块可以在不同的处理器架构上运行
- **页面映射器(PageMapper)**- 提供对虚拟地址和物理地址的映射,以及页表的创建、填写、销毁、权限管理等操作。分为两种类型:内核页表映射器(KernelMapper)和用户页表映射器(位于具体的用户地址空间结构中)
- **页面刷新器(PageFlusher)** - 提供对页表的刷新操作(整表刷新、单页刷新、跨核心刷新)
- **页帧分配器(FrameAllocator)** - 提供对页帧的分配、释放、管理等操作。具体来说,包括BumpAllocator、BuddyAllocator
- **小对象分配器** - 提供对小内存对象的分配、释放、管理等操作。指的是内核里面的SlabAllocator (SlabAllocator的实现目前还没有完成)
- **MMIO空间管理器** - 提供对MMIO地址空间的分配、管理操作。(目前这个模块待进一步重构)
- **用户地址空间管理机制** - 提供对用户地址空间的管理。
    - VMA机制 - 提供对用户地址空间的管理,包括VMA的创建、销毁、权限管理等操作
    - 用户映射管理 - 与VMA机制共同作用,管理用户地址空间的映射
- **系统调用层** - 提供对用户空间的内存管理系统调用,包括mmap、munmap、mprotect、mremap等
- **C接口兼容层** - 提供对原有的C代码的接口,是的C代码能够正常运行。


除上面的新增内容以外,其它的更改内容:
- 新增二进制加载器,以及elf的解析器
- 解决由于local_irq_save、local_irq_restore函数的汇编不规范导致影响栈行为的bug。
- 解决local_irq_save未关中断的错误。
- 修复sys_gettimeofday对timezone参数的处理的bug
2023-07-22 16:22:17 +08:00

232 lines
8.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::sync::atomic::compiler_fence;
use alloc::{boxed::Box, collections::LinkedList, vec::Vec};
use crate::{
arch::asm::current::current_pcb,
include::bindings::bindings::{
process_control_block, MAX_CPU_NUM, PF_NEED_SCHED, SCHED_FIFO, SCHED_RR,
},
kBUG, kdebug,
libs::spinlock::RawSpinlock,
};
use super::core::{sched_enqueue, Scheduler};
/// 声明全局的rt调度器实例
pub static mut RT_SCHEDULER_PTR: Option<Box<SchedulerRT>> = None;
/// @brief 获取rt调度器实例的可变引用
#[inline]
pub fn __get_rt_scheduler() -> &'static mut SchedulerRT {
return unsafe { RT_SCHEDULER_PTR.as_mut().unwrap() };
}
/// @brief 初始化rt调度器
pub unsafe fn sched_rt_init() {
kdebug!("rt scheduler init");
if RT_SCHEDULER_PTR.is_none() {
RT_SCHEDULER_PTR = Some(Box::new(SchedulerRT::new()));
} else {
kBUG!("Try to init RT Scheduler twice.");
panic!("Try to init RT Scheduler twice.");
}
}
/// @brief RT队列per-cpu的
#[derive(Debug)]
struct RTQueue {
/// 队列的锁
lock: RawSpinlock,
/// 存储进程的双向队列
queue: LinkedList<&'static mut process_control_block>,
}
impl RTQueue {
pub fn new() -> RTQueue {
RTQueue {
queue: LinkedList::new(),
lock: RawSpinlock::INIT,
}
}
/// @brief 将pcb加入队列
pub fn enqueue(&mut self, pcb: &'static mut process_control_block) {
let mut rflags = 0usize;
self.lock.lock_irqsave(&mut rflags);
// 如果进程是IDLE进程那么就不加入队列
if pcb.pid == 0 {
self.lock.unlock_irqrestore(rflags);
return;
}
self.queue.push_back(pcb);
self.lock.unlock_irqrestore(rflags);
}
/// @brief 将pcb从调度队列头部取出,若队列为空则返回None
pub fn dequeue(&mut self) -> Option<&'static mut process_control_block> {
let res: Option<&'static mut process_control_block>;
let mut rflags = 0usize;
self.lock.lock_irqsave(&mut rflags);
if self.queue.len() > 0 {
// 队列不为空返回下一个要执行的pcb
res = Some(self.queue.pop_front().unwrap());
} else {
// 如果队列为空则返回None
res = None;
}
self.lock.unlock_irqrestore(rflags);
return res;
}
pub fn enqueue_front(&mut self, pcb: &'static mut process_control_block) {
let mut rflags = 0usize;
self.lock.lock_irqsave(&mut rflags);
// 如果进程是IDLE进程那么就不加入队列
if pcb.pid == 0 {
self.lock.unlock_irqrestore(rflags);
return;
}
self.queue.push_front(pcb);
self.lock.unlock_irqrestore(rflags);
}
pub fn get_rt_queue_size(&mut self) -> usize {
return self.queue.len();
}
}
/// @brief RT调度器类
pub struct SchedulerRT {
cpu_queue: Vec<Vec<&'static mut RTQueue>>,
load_list: Vec<&'static mut LinkedList<u64>>,
}
impl SchedulerRT {
const RR_TIMESLICE: i64 = 100;
const MAX_RT_PRIO: i64 = 100;
pub fn new() -> SchedulerRT {
// 暂时手动指定核心数目
// todo: 从cpu模块来获取核心的数目
let mut result = SchedulerRT {
cpu_queue: Default::default(),
load_list: Default::default(),
};
// 为每个cpu核心创建队列
for cpu_id in 0..MAX_CPU_NUM {
result.cpu_queue.push(Vec::new());
// 每个CPU有MAX_RT_PRIO个优先级队列
for _ in 0..SchedulerRT::MAX_RT_PRIO {
result.cpu_queue[cpu_id as usize].push(Box::leak(Box::new(RTQueue::new())));
}
}
// 为每个cpu核心创建负载统计队列
for _ in 0..MAX_CPU_NUM {
result
.load_list
.push(Box::leak(Box::new(LinkedList::new())));
}
return result;
}
/// @brief 挑选下一个可执行的rt进程
pub fn pick_next_task_rt(&mut self, cpu_id: u32) -> Option<&'static mut process_control_block> {
// 循环查找,直到找到
// 这里应该是优先级数量而不是CPU数量需要修改
for i in 0..SchedulerRT::MAX_RT_PRIO {
let cpu_queue_i: &mut RTQueue = self.cpu_queue[cpu_id as usize][i as usize];
let proc: Option<&'static mut process_control_block> = cpu_queue_i.dequeue();
if proc.is_some() {
return proc;
}
}
// return 一个空值
None
}
pub fn rt_queue_len(&mut self, cpu_id: u32) -> usize {
let mut sum = 0;
for prio in 0..SchedulerRT::MAX_RT_PRIO {
sum += self.cpu_queue[cpu_id as usize][prio as usize].get_rt_queue_size();
}
return sum as usize;
}
#[allow(dead_code)]
#[inline]
pub fn load_list_len(&mut self, cpu_id: u32) -> usize {
return self.load_list[cpu_id as usize].len();
}
pub fn enqueue_front(&mut self, pcb: &'static mut process_control_block) {
self.cpu_queue[pcb.cpu_id as usize][pcb.priority as usize].enqueue_front(pcb);
}
}
impl Scheduler for SchedulerRT {
/// @brief 在当前cpu上进行调度。
/// 请注意,进入该函数之前,需要关中断
fn sched(&mut self) -> Option<&'static mut process_control_block> {
current_pcb().flags &= !(PF_NEED_SCHED as u64);
// 正常流程下这里一定是会pick到next的pcb的如果是None的话要抛出错误
let cpu_id = current_pcb().cpu_id;
let proc: &'static mut process_control_block =
self.pick_next_task_rt(cpu_id).expect("No RT process found");
// 如果是fifo策略则可以一直占有cpu直到有优先级更高的任务就绪(即使优先级相同也不行)或者主动放弃(等待资源)
if proc.policy == SCHED_FIFO {
// 如果挑选的进程优先级小于当前进程,则不进行切换
if proc.priority <= current_pcb().priority {
sched_enqueue(proc, false);
} else {
// 将当前的进程加进队列
sched_enqueue(current_pcb(), false);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Some(proc);
}
}
// RR调度策略需要考虑时间片
else if proc.policy == SCHED_RR {
// 同等优先级的,考虑切换
if proc.priority >= current_pcb().priority {
// 判断这个进程时间片是否耗尽,若耗尽则将其时间片赋初值然后入队
if proc.rt_time_slice <= 0 {
proc.rt_time_slice = SchedulerRT::RR_TIMESLICE;
proc.flags |= !(PF_NEED_SCHED as u64);
sched_enqueue(proc, false);
}
// 目标进程时间片未耗尽,切换到目标进程
else {
// 将当前进程加进队列
sched_enqueue(current_pcb(), false);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Some(proc);
}
}
// curr优先级更大说明一定是实时进程将所选进程入队列此时需要入队首
else {
self.cpu_queue[cpu_id as usize][proc.cpu_id as usize].enqueue_front(proc);
}
}
return None;
}
fn enqueue(&mut self, pcb: &'static mut process_control_block) {
let cpu_id = pcb.cpu_id;
let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize];
cpu_queue[cpu_id as usize].enqueue(pcb);
// // 获取当前时间
// let time = unsafe { _rdtsc() };
// let freq = unsafe { Cpu_tsc_freq };
// // kdebug!("this is timeeeeeeer {},freq is {}, {}", time, freq, cpu_id);
// // 将当前时间加入负载记录队列
// self.load_list[cpu_id as usize].push_back(time);
// // 如果队首元素与当前时间差超过设定值,则移除队首元素
// while self.load_list[cpu_id as usize].len() > 1
// && (time - *self.load_list[cpu_id as usize].front().unwrap() > 10000000000)
// {
// self.load_list[cpu_id as usize].pop_front();
// }
}
}