mod context; mod switch; mod task; use crate::loader::{get_num_app, get_app_data}; use crate::trap::TrapContext; use crate::sync::UPSafeCell; use lazy_static::*; use switch::__switch; use task::{TaskControlBlock, TaskStatus}; use alloc::vec::Vec; pub use context::TaskContext; pub struct TaskManager { num_app: usize, inner: UPSafeCell, } struct TaskManagerInner { tasks: Vec, current_task: usize, } lazy_static! { pub static ref TASK_MANAGER: TaskManager = { println!("init TASK_MANAGER"); let num_app = get_num_app(); println!("num_app = {}", num_app); let mut tasks: Vec = Vec::new(); for i in 0..num_app { tasks.push(TaskControlBlock::new( get_app_data(i), i, )); } TaskManager { num_app, inner: unsafe { UPSafeCell::new(TaskManagerInner { tasks, current_task: 0, })}, } }; } impl TaskManager { fn run_first_task(&self) { let next_task = &mut self.inner.upsafe_access().tasks[0]; next_task.task_status = TaskStatus::Running; let next_task_cx_ptr = &next_task.task_cx as *const TaskContext; drop(next_task); let mut _unused = TaskContext::zero_init(); unsafe { __switch( &mut _unused as *mut _, next_task_cx_ptr, ); } } fn mark_current_suspended(&self) { let inner = self.inner.upsafe_access(); inner.tasks[inner.current_task].task_status = TaskStatus::Ready; } fn mark_current_exited(&self) { let inner = self.inner.upsafe_access(); inner.tasks[inner.current_task].task_status = TaskStatus::Exited; } fn find_next_task(&self) -> Option { let inner = self.inner.upsafe_access(); let current = inner.current_task; (current + 1..current + self.num_app + 1) .map(|id| id % self.num_app) .find(|id| { inner.tasks[*id].task_status == TaskStatus::Ready }) } fn get_current_token(&self) -> usize { let inner = self.inner.upsafe_access(); inner.tasks[inner.current_task].get_user_token() } fn get_current_trap_cx(&self) -> &mut TrapContext { let inner = self.inner.upsafe_access(); inner.tasks[inner.current_task].get_trap_cx() } fn run_next_task(&self) { if let Some(next) = self.find_next_task() { let mut inner = self.inner.upsafe_access(); let current = inner.current_task; inner.tasks[next].task_status = TaskStatus::Running; inner.current_task = next; let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext; let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext; drop(inner); unsafe { __switch( current_task_cx_ptr, next_task_cx_ptr, ); } } else { panic!("All applications completed!"); } } } pub fn run_first_task() { TASK_MANAGER.run_first_task(); } fn run_next_task() { TASK_MANAGER.run_next_task(); } fn mark_current_suspended() { TASK_MANAGER.mark_current_suspended(); } fn mark_current_exited() { TASK_MANAGER.mark_current_exited(); } pub fn suspend_current_and_run_next() { mark_current_suspended(); run_next_task(); } pub fn exit_current_and_run_next() { mark_current_exited(); run_next_task(); } pub fn current_user_token() -> usize { TASK_MANAGER.get_current_token() } pub fn current_trap_cx() -> &'static mut TrapContext { TASK_MANAGER.get_current_trap_cx() }