进程管理的核心结构以及0号进程的创建
parent
2f40dbce77
commit
d1dc7056a5
@ -0,0 +1,46 @@
|
||||
use alloc::collections::VecDeque;
|
||||
use alloc::sync::Arc;
|
||||
use lazy_static::lazy_static;
|
||||
use crate::println;
|
||||
use crate::task::task::TaskControlBlock;
|
||||
use crate::task::UPSafeCell;
|
||||
|
||||
/// 任务管理器 仅负责管理所有任务, 由ch4 TaskManager 拆分的,
|
||||
/// 先入先出的双端队列
|
||||
pub struct TaskManager {
|
||||
ready_queue: VecDeque<Arc<TaskControlBlock>>,
|
||||
}
|
||||
|
||||
impl TaskManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ready_queue: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TaskManager {
|
||||
// 添加一个任务到 队列中
|
||||
pub fn add(&mut self, task: Arc<TaskControlBlock>) {
|
||||
self.ready_queue.push_back(task);
|
||||
}
|
||||
// 如果有任务, 弹出第一个任务
|
||||
pub fn fetch(&mut self) -> Option<Arc<TaskControlBlock>> {
|
||||
self.ready_queue.pop_front()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
lazy_static! {
|
||||
// 全局的任务管理器
|
||||
pub static ref TASK_MANAGER: UPSafeCell<TaskManager> = unsafe { UPSafeCell::new(TaskManager::new()) };
|
||||
}
|
||||
/// 给全局任务管理器添加任务
|
||||
pub fn add_task(task: Arc<TaskControlBlock>) {
|
||||
TASK_MANAGER.exclusive_access().add(task);
|
||||
}
|
||||
// 全局任务管理器 弹出任务
|
||||
pub fn pop_task() -> Option<Arc<TaskControlBlock>> {
|
||||
TASK_MANAGER.exclusive_access().fetch()
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
use alloc::sync::Arc;
|
||||
use lazy_static::lazy_static;
|
||||
use crate::task::context::TaskContext;
|
||||
use crate::task::switch::__switch;
|
||||
use crate::task::task::{TaskControlBlock, TaskStatus};
|
||||
use crate::trap::TrapContext;
|
||||
use crate::sync::UPSafeCell;
|
||||
use crate::task::manager::{pop_task, TASK_MANAGER};
|
||||
use crate::timer::get_time_us;
|
||||
|
||||
///维护在一个处理器上正在执行的任务, 这在ch4 中是 TaskManager做的, 现在拆分
|
||||
pub struct Processor {
|
||||
/// 当前处理器上正在执行的任务, 他是一个被option 包裹的 智能指针, 保证 TCB 要不在这个结构体中, 要不就是在全局的任务管理器上
|
||||
current: Option<Arc<TaskControlBlock>>,
|
||||
/// 当前处理器上的 idle 控制流的任务上下文, 当任务切换的时候, 先切换到这个
|
||||
/// 这样做的主要目的是使得换入/换出进程和调度执行流在内核层各自执行在不同的内核栈上,
|
||||
/// 分别是进程自身的内核栈和内核初始化时使用的启动栈
|
||||
/// 这样的话, 调度相关的数据不会出现在进程内核栈上,
|
||||
/// 也使得调度机制对于换出进程的Trap执行流是不可见的
|
||||
/// 它在决定换出的时候只需调用schedule而无需操心调度的事情
|
||||
/// 从而各执行流的分工更加明确了, 虽然带来了更大的开销
|
||||
/// 虽然 永远不会执行这个 task context 的任务, 他只保存 内核的启动栈
|
||||
idle_task_cx: TaskContext,
|
||||
pub clock_time: usize, // 处理器时间
|
||||
}
|
||||
|
||||
|
||||
impl Processor {
|
||||
///Create an empty Processor
|
||||
/// 一旦程序开始运行, 就开始在内核栈或者用户栈之间切换, 永远 不会运行到这个, 这个就是保存 内核的启动栈的
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
current: None,
|
||||
idle_task_cx: TaskContext::new(),
|
||||
clock_time: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Processor {
|
||||
// 得到当前 task context 的指针
|
||||
fn get_idle_task_cx_ptr(&mut self) -> *mut TaskContext {
|
||||
&mut self.idle_task_cx as *mut _
|
||||
}
|
||||
/// 取出当前正在执行的任务
|
||||
pub fn take_current(&mut self) -> Option<Arc<TaskControlBlock>> {
|
||||
self.current.take()
|
||||
}
|
||||
|
||||
///当前正在执行的任务的 copy
|
||||
pub fn current(&self) -> Option<Arc<TaskControlBlock>> {
|
||||
self.current.as_ref().map(Arc::clone)
|
||||
}
|
||||
|
||||
// 掐表函数
|
||||
fn refresh_stop_clock(&mut self) -> usize {
|
||||
// 上次停表的时间
|
||||
let start_time = self.clock_time;
|
||||
// 当前时间
|
||||
self.clock_time = get_time_us();
|
||||
// 返回 当前时间 - 上次停表时间 = 时间间距
|
||||
self.clock_time - start_time
|
||||
}
|
||||
|
||||
// 即将进入用户态, 把之前使用的内核时间统计
|
||||
pub fn user_time_start(&mut self) {
|
||||
let use_clock_time = self.refresh_stop_clock();
|
||||
self.current.as_ref().unwrap().inner_exclusive_access().kernel_time += use_clock_time;
|
||||
}
|
||||
pub fn kernel_time_start(&mut self) {
|
||||
let use_clock_time = self.refresh_stop_clock();
|
||||
self.current.as_ref().unwrap().inner_exclusive_access().user_time += use_clock_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 全局 描述cpu状态的管理器
|
||||
lazy_static! {
|
||||
pub static ref PROCESSOR: UPSafeCell<Processor> = unsafe { UPSafeCell::new(Processor::new()) };
|
||||
}
|
||||
|
||||
|
||||
// 循环 全局的任务管理器'fetch_task'获取需要运行的下一个进程, 并通过'__switch' 和当前process切换进程,
|
||||
// 这和之前的 run_first_task 差不多
|
||||
pub fn run_tasks() {
|
||||
loop {
|
||||
// 获得当前 进程的管理对象
|
||||
let mut processor = PROCESSOR.exclusive_access();
|
||||
|
||||
// 弹出一个任务
|
||||
if let Some(task) = pop_task() {
|
||||
// 当前运行的进程(第一次运行时,这里是空的 zero, 但是不影响, 因为永远不会执行到第一次运行的任务)
|
||||
let idle_task_cx_ptr = processor.get_idle_task_cx_ptr();
|
||||
|
||||
// 获得下一个需要运行的进程 的task context的指针
|
||||
let mut task_inner = task.inner_exclusive_access();
|
||||
let next_task_cx_ptr = &task_inner.task_cx as *const TaskContext;
|
||||
task_inner.task_status = TaskStatus::Running;
|
||||
|
||||
// 删除内部可变性的引用, 这里需要手动释放
|
||||
drop(task_inner);
|
||||
|
||||
// 修改process的状态, 把下一个需要运行的进程 move到 Process中被管理, 保证引用计数为1
|
||||
processor.current = Some(task);
|
||||
|
||||
// 这里需要手动释放, 同上, 因为switch跳出作用域了, 不会通过作用域自动析构 refcell
|
||||
drop(processor);
|
||||
|
||||
unsafe {
|
||||
__switch(idle_task_cx_ptr, next_task_cx_ptr);
|
||||
|
||||
// 调用 schedule 之后 内部又调用__switch, next task 也就是idle task会走入到这里, 开启新的循环获取新的任务
|
||||
// 其实 idle task 并不会执行, 他只是保存 内核的启动栈 也就是当前函数 的寄存器状态
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 取出当前正在执行的任务
|
||||
pub fn take_current_task() -> Option<Arc<TaskControlBlock>> {
|
||||
PROCESSOR.exclusive_access().take_current()
|
||||
}
|
||||
|
||||
// 返回当前正在执行的任务的 copy版本
|
||||
pub fn current_task() -> Option<Arc<TaskControlBlock>> {
|
||||
PROCESSOR.exclusive_access().current()
|
||||
}
|
||||
|
||||
//得到当前正在执行任务的token
|
||||
pub fn current_user_token() -> usize {
|
||||
// 得到当前正在执行的任务
|
||||
let task = current_task().unwrap();
|
||||
// 得到当前正在执行任务的token
|
||||
let token = task.inner_exclusive_access().get_user_token();
|
||||
token
|
||||
}
|
||||
|
||||
// 得到当前 task context 的指针
|
||||
pub fn current_trap_cx() -> &'static mut TrapContext {
|
||||
current_task()
|
||||
.unwrap()
|
||||
.inner_exclusive_access()
|
||||
.get_trap_cx()
|
||||
}
|
||||
|
||||
// 扩张/缩减, 当前运行进程的地址空间中的堆段, 指定字节的数据
|
||||
pub fn change_program_brk(size: i32) -> Option<usize> {
|
||||
current_task().as_ref().unwrap().inner_exclusive_access().change_program_brk(size)
|
||||
}
|
||||
|
||||
|
||||
// 传入当前运行的任务指针, 切换到 idle 任务
|
||||
// 用尽时间片, 或者调用 yield之后会调用这个, 调用这个之后, 会回到 run_task __switch返回的位置, 开启下一轮循环 中执行
|
||||
pub fn schedule(switched_task_cx_ptr: *mut TaskContext) {
|
||||
// 进程管理对象
|
||||
let mut processor = PROCESSOR.exclusive_access();
|
||||
|
||||
// 得到当前进程管理中 task context 指针
|
||||
let idle_task_cx_ptr = processor.get_idle_task_cx_ptr();
|
||||
drop(processor);
|
||||
|
||||
// 切换 汇编会保存当前的寄存器状态到 switched_task_cx_ptr 中, 然后根据 idle_task_cx_ptr 继续执行 __switch 的下一行, 结束当前循环, 开启新的循环
|
||||
unsafe {
|
||||
__switch(switched_task_cx_ptr, idle_task_cx_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue