diff --git a/os/src/main.rs b/os/src/main.rs index 145f50a1..0f04c1fe 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -43,10 +43,18 @@ pub fn rust_main() -> ! { mm::init(); println!("[kernel] back to world!"); mm::remap_test(); + + // add apps + let num_app = loader::get_num_app(); + println!("num_app={}", num_app); + for i in 0..num_app { + println!("i={}", i); + task::add_application(loader::get_app_data(i), i); + } trap::init(); - //trap::enable_interrupt(); trap::enable_timer_interrupt(); timer::set_next_trigger(); - task::run_first_task(); + println!("before task::run_tasks!"); + task::run_tasks(); panic!("Unreachable in rust_main!"); } \ No newline at end of file diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs new file mode 100644 index 00000000..1b9a5ad8 --- /dev/null +++ b/os/src/task/manager.rs @@ -0,0 +1,34 @@ +use super::TaskControlBlock; +use alloc::collections::VecDeque; +use alloc::sync::Arc; +use spin::Mutex; +use lazy_static::*; + +pub struct TaskManager { + ready_queue: VecDeque>>, +} + +/// A simple FIFO scheduler. +impl TaskManager { + pub fn new() -> Self { + Self { ready_queue: VecDeque::new(), } + } + pub fn add(&mut self, task: Arc>) { + self.ready_queue.push_back(task); + } + pub fn fetch(&mut self) -> Option>> { + self.ready_queue.pop_front() + } +} + +lazy_static! { + pub static ref TASK_MANAGER: Mutex = Mutex::new(TaskManager::new()); +} + +pub fn add_task(task: Arc>) { + TASK_MANAGER.lock().add(task); +} + +pub fn fetch_task() -> Option>> { + TASK_MANAGER.lock().fetch() +} \ No newline at end of file diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 009829e7..eaf7ced2 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -1,6 +1,8 @@ mod context; mod switch; mod task; +mod manager; +mod processor; use crate::loader::{get_num_app, get_app_data}; use crate::trap::TrapContext; @@ -9,141 +11,38 @@ use lazy_static::*; use switch::__switch; use task::{TaskControlBlock, TaskStatus}; use alloc::vec::Vec; +use alloc::sync::Arc; +use spin::Mutex; +use manager::fetch_task; pub use context::TaskContext; - -pub struct TaskManager { - num_app: usize, - inner: RefCell, -} - -struct TaskManagerInner { - tasks: Vec, - current_task: usize, -} - -unsafe impl Sync for TaskManager {} - -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: RefCell::new(TaskManagerInner { - tasks, - current_task: 0, - }), - } - }; -} - -impl TaskManager { - fn run_first_task(&self) { - self.inner.borrow_mut().tasks[0].task_status = TaskStatus::Running; - let next_task_cx = self.inner.borrow().tasks[0].get_task_cx_ptr2(); - let _unused: usize = 0; - unsafe { - __switch( - &_unused as *const _, - next_task_cx, - ); - } - } - - fn mark_current_suspended(&self) { - let mut inner = self.inner.borrow_mut(); - let current = inner.current_task; - inner.tasks[current].task_status = TaskStatus::Ready; - } - - fn mark_current_exited(&self) { - let mut inner = self.inner.borrow_mut(); - let current = inner.current_task; - inner.tasks[current].task_status = TaskStatus::Exited; - } - - fn find_next_task(&self) -> Option { - let inner = self.inner.borrow(); - 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.borrow(); - let current = inner.current_task; - inner.tasks[current].get_user_token() - } - - fn get_current_trap_cx(&self) -> &mut TrapContext { - let inner = self.inner.borrow(); - let current = inner.current_task; - inner.tasks[current].get_trap_cx() - } - - fn run_next_task(&self) { - if let Some(next) = self.find_next_task() { - let mut inner = self.inner.borrow_mut(); - let current = inner.current_task; - inner.tasks[next].task_status = TaskStatus::Running; - inner.current_task = next; - let current_task_cx = inner.tasks[current].get_task_cx_ptr2(); - let next_task_cx = inner.tasks[next].get_task_cx_ptr2(); - core::mem::drop(inner); - unsafe { - __switch( - current_task_cx, - next_task_cx, - ); - } - } 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 use processor::{ + run_tasks, + current_task, + current_user_token, + current_trap_cx, + take_current_task, + schedule, +}; +pub use manager::add_task; pub fn suspend_current_and_run_next() { - mark_current_suspended(); - run_next_task(); + // There must be an application running. + let task = current_task().unwrap(); + let task_cx_ptr = task.lock().get_task_cx_ptr2(); + // Change status to Ready. + task.lock().task_status = TaskStatus::Ready; + // push back to ready queue. + add_task(task); + // jump to scheduling cycle + schedule(task_cx_ptr); } pub fn exit_current_and_run_next() { - mark_current_exited(); - run_next_task(); + // The resource recycle mechanism needs child processes. Now we just panic! + panic!("An application exited!"); } -pub fn current_user_token() -> usize { - TASK_MANAGER.get_current_token() +pub fn add_application(elf_data: &[u8], app_id: usize) { + add_task(Arc::new(Mutex::new(TaskControlBlock::new(elf_data, app_id)))); } - -pub fn current_trap_cx() -> &'static mut TrapContext { - TASK_MANAGER.get_current_trap_cx() -} \ No newline at end of file diff --git a/os/src/task/processor.rs b/os/src/task/processor.rs new file mode 100644 index 00000000..5551fb72 --- /dev/null +++ b/os/src/task/processor.rs @@ -0,0 +1,96 @@ +use super::TaskControlBlock; +use alloc::sync::Arc; +use spin::Mutex; +use lazy_static::*; +use super::{add_task, fetch_task}; +use super::__switch; +use crate::trap::TrapContext; + +pub struct Processor { + inner: Mutex, +} + +unsafe impl Sync for Processor {} + +struct ProcessorInner { + current: Option>>, + idle_task_cx_ptr: usize, +} + +impl Processor { + pub fn new() -> Self { + Self { + inner: Mutex::new(ProcessorInner { + current: None, + idle_task_cx_ptr: 0, + }), + } + } + fn get_idle_task_cx_ptr2(&self) -> *const usize { + let inner = self.inner.lock(); + &inner.idle_task_cx_ptr as *const usize + } + pub fn run(&self) { + //println!("into Processor::run"); + loop { + if let Some(task) = fetch_task() { + //println!("found task!"); + let idle_task_cx_ptr = self.get_idle_task_cx_ptr2(); + let next_task_cx_ptr = task.lock().get_task_cx_ptr2(); + //println!("next_task_cx_ptr={:p}", next_task_cx_ptr); + self.inner.lock().current = Some(task); + unsafe { + __switch( + idle_task_cx_ptr, + next_task_cx_ptr, + ); + } + } + } + } + pub fn take_current(&self) -> Option>> { + self.inner.lock().current.take() + } + pub fn current(&self) -> Option>> { + self.inner.lock().current.as_ref().map(|task| task.clone()) + } +} + +lazy_static! { + pub static ref PROCESSOR: Processor = Processor::new(); +} + +pub fn run_tasks() { + PROCESSOR.run(); +} + +pub fn take_current_task() -> Option>> { + PROCESSOR.take_current() +} + +pub fn current_task() -> Option>> { + //println!("into current_task!"); + PROCESSOR.current() +} + +pub fn current_user_token() -> usize { + //println!("into current_user_token!"); + let task = current_task().unwrap(); + //println!("Got task in current_user_token!"); + let token = task.lock().get_user_token(); + token +} + +pub fn current_trap_cx() -> &'static mut TrapContext { + current_task().unwrap().as_ref().lock().get_trap_cx() +} + +pub fn schedule(switched_task_cx_ptr2: *const usize) { + let idle_task_cx_ptr2 = PROCESSOR.get_idle_task_cx_ptr2(); + unsafe { + __switch( + switched_task_cx_ptr2, + idle_task_cx_ptr2, + ); + } +} diff --git a/os/src/task/task.rs b/os/src/task/task.rs index 8e38635b..db1eea83 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -4,11 +4,14 @@ use crate::config::{TRAP_CONTEXT, kernel_stack_position}; use super::TaskContext; pub struct TaskControlBlock { + // immutable + pub trap_cx_ppn: PhysPageNum, + pub base_size: usize, + //pub pid: usize, + // mutable pub task_cx_ptr: usize, pub task_status: TaskStatus, pub memory_set: MemorySet, - pub trap_cx_ppn: PhysPageNum, - pub base_size: usize, } impl TaskControlBlock { @@ -65,4 +68,5 @@ pub enum TaskStatus { Ready, Running, Exited, + Zombie, } \ No newline at end of file diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 46e113bb..01d096f5 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -83,6 +83,7 @@ pub fn trap_handler() -> ! { #[no_mangle] pub fn trap_return() -> ! { + //println!("into trap_return!"); set_user_trap_entry(); let trap_cx_ptr = TRAP_CONTEXT; let user_satp = current_user_token(); @@ -91,6 +92,7 @@ pub fn trap_return() -> ! { fn __restore(); } let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE; + //println!("before jr!"); unsafe { llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile"); }