From 601d0f85bde9200af72d66ef7e0e5916b1af1d6f Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 20 May 2018 15:37:48 +0800 Subject: [PATCH] Add an event system in the Processor. Can sleep and wakeup. --- Makefile | 4 ++ src/arch/x86_64/interrupt/handler.rs | 4 +- src/arch/x86_64/paging/mod.rs | 5 +- src/lib.rs | 3 +- src/process/mod.rs | 25 +++++--- src/process/process.rs | 3 +- src/process/processor.rs | 84 +++++++++++++++++++++----- src/schedule.rs | 89 ---------------------------- src/syscall.rs | 2 +- src/util.rs | 84 ++++++++++++++++++++++++++ 10 files changed, 180 insertions(+), 123 deletions(-) delete mode 100644 src/schedule.rs diff --git a/Makefile b/Makefile index 9db3fe0..d89f04d 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,10 @@ features := $(features) test qemu_opts := $(qemu_opts) -device isa-debug-exit endif +ifdef int +qemu_opts := $(qemu_opts) -d int +endif + ifeq ($(OS),Windows_NT) uname := Win32 diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs index 3dd83da..cdd3a28 100644 --- a/src/arch/x86_64/interrupt/handler.rs +++ b/src/arch/x86_64/interrupt/handler.rs @@ -72,8 +72,8 @@ interrupt!(com2, { }); interrupt_switch!(timer, stack, rsp, { - use schedule; - schedule::timer_handler(stack, &mut rsp); + use process; + process::timer_handler(stack, &mut rsp); ack(IRQ_TIMER); }); diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs index b0cf4a3..94a1eb8 100644 --- a/src/arch/x86_64/paging/mod.rs +++ b/src/arch/x86_64/paging/mod.rs @@ -144,11 +144,10 @@ impl ActivePageTable { pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { use x86_64::PhysicalAddress; use x86_64::registers::control_regs; + debug!("switch table to {:?}", new_table.p4_frame); let old_table = InactivePageTable { - p4_frame: Frame::of_addr( - control_regs::cr3().0 as usize - ), + p4_frame: Frame::of_addr(control_regs::cr3().0 as usize), }; unsafe { control_regs::cr3_write(new_table.p4_frame.start_address()); diff --git a/src/lib.rs b/src/lib.rs index f0e614d..8bbcb91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,6 @@ mod consts; mod process; mod syscall; mod fs; -mod schedule; #[allow(dead_code)] #[cfg(target_arch = "x86_64")] @@ -106,7 +105,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { loop{ println!("init ..."); let mut i = 0; - while i < 1 << 22 { + while i < 1 << 23 { i += 1; } } diff --git a/src/process/mod.rs b/src/process/mod.rs index f4af443..7e5afd9 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -31,18 +31,11 @@ pub fn init(mut mc: MemoryController) { static PROCESSOR: Once> = Once::new(); static MC: Once> = Once::new(); -/// Called by timer handler in arch -/// 设置rsp,指向接下来要执行线程的 内核栈顶 -/// 之后中断处理例程会重置rsp,恢复对应线程的上下文 -pub fn schedule(rsp: &mut usize) { - PROCESSOR.try().unwrap().lock().schedule(rsp); -} - extern fn idle_thread() { loop { println!("idle ..."); let mut i = 0; - while i < 1 << 22 { + while i < 1 << 23 { i += 1; } } @@ -97,7 +90,21 @@ pub fn sys_exit(rsp: &mut usize, error_code: ErrorCode) -> i32 { pub fn sys_sleep(rsp: &mut usize, time: usize) -> i32 { info!("sleep: {} ticks", time); - unimplemented!() + let mut processor = PROCESSOR.try().unwrap().lock(); + let pid = processor.current().pid; + processor.schedule(rsp); + processor.sleep(pid, time); + 0 +} + +pub fn sys_get_time() -> i32 { + let processor = PROCESSOR.try().unwrap().lock(); + processor.get_time() as i32 +} + +pub fn timer_handler(tf: &TrapFrame, rsp: &mut usize) { + let mut processor = PROCESSOR.try().unwrap().lock(); + processor.tick(rsp); } pub fn add_user_process(name: impl AsRef, data: &[u8]) { diff --git a/src/process/process.rs b/src/process/process.rs index b4ed3f5..968e717 100644 --- a/src/process/process.rs +++ b/src/process/process.rs @@ -24,7 +24,8 @@ pub type ErrorCode = usize; pub enum Status { Ready, Running, - Sleeping(Pid), + Waiting(Pid), + Sleeping, Exited(ErrorCode), } diff --git a/src/process/processor.rs b/src/process/processor.rs index b2bc370..6444452 100644 --- a/src/process/processor.rs +++ b/src/process/processor.rs @@ -3,10 +3,15 @@ use memory::{ActivePageTable, InactivePageTable}; use super::*; use core::cell::RefCell; use core::fmt::{Debug, Formatter, Error}; +use util::{EventHub, GetMut2}; pub struct Processor { procs: BTreeMap, current_pid: Pid, + event_hub: EventHub, + /// All kernel threads share one page table. + /// When running user process, it will be stored here. + kernel_page_table: Option, } impl Processor { @@ -14,6 +19,12 @@ impl Processor { Processor { procs: BTreeMap::::new(), current_pid: 0, + event_hub: { + let mut e = EventHub::new(); + e.push(100, Event::Schedule); + e + }, + kernel_page_table: None, } } @@ -29,6 +40,29 @@ impl Processor { return next; } + /// Called by timer. + /// Handle events. + pub fn tick(&mut self, rsp: &mut usize) { + self.event_hub.tick(); + while let Some(event) = self.event_hub.pop() { + debug!("Processor: event {:?}", event); + match event { + Event::Schedule => { + self.event_hub.push(100, Event::Schedule); + self.schedule(rsp); + }, + Event::Wakeup(pid) => { + self.get_mut(pid).status = Status::Ready; + self.switch_to(pid, rsp); + }, + } + } + } + + pub fn get_time(&self) -> usize { + self.event_hub.get_time() + } + pub fn add(&mut self, mut process: Process) -> Pid { let pid = self.alloc_pid(); process.pid = pid; @@ -61,7 +95,7 @@ impl Processor { } self.current_pid = pid; - let (from, to) = self.get_mut2(pid0, pid); + let (from, to) = self.procs.get_mut2(pid0, pid); // set `from` if from.status == Status::Running { @@ -75,10 +109,18 @@ impl Processor { *rsp = to.rsp; // switch page table - if let Some(page_table) = to.page_table.take() { + if from.is_user || to.is_user { + let (from_pt, to_pt) = match (from.is_user, to.is_user) { + (true, true) => (&mut from.page_table, &mut to.page_table), + (true, false) => (&mut from.page_table, &mut self.kernel_page_table), + (false, true) => (&mut self.kernel_page_table, &mut to.page_table), + _ => panic!(), + }; + assert!(from_pt.is_none()); + assert!(to_pt.is_some()); let mut active_table = unsafe { ActivePageTable::new() }; - let old_table = active_table.switch(page_table); - from.page_table = Some(old_table); + let old_table = active_table.switch(to_pt.take().unwrap()); + *from_pt = Some(old_table); } info!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp); @@ -90,14 +132,6 @@ impl Processor { fn get_mut(&mut self, pid: Pid) -> &mut Process { self.procs.get_mut(&pid).unwrap() } - fn get_mut2(&mut self, pid1: Pid, pid2: Pid) -> (&mut Process, &mut Process) { - assert_ne!(pid1, pid2); - let procs1 = &mut self.procs as *mut BTreeMap<_, _>; - let procs2 = procs1; - let p1 = unsafe { &mut *procs1 }.get_mut(&pid1).unwrap(); - let p2 = unsafe { &mut *procs2 }.get_mut(&pid2).unwrap(); - (p1, p2) - } pub fn current(&self) -> &Process { self.get(self.current_pid) } @@ -121,6 +155,11 @@ impl Processor { } } + pub fn sleep(&mut self, pid: Pid, time: usize) { + self.get_mut(pid).status = Status::Sleeping; + self.event_hub.push(time, Event::Wakeup(pid)); + } + /// Let current process wait for another pub fn current_wait_for(&mut self, target: WaitTarget) -> WaitResult { // Find one target process and it's exit code @@ -145,15 +184,15 @@ impl Processor { } else { info!("Processor: {} wait for {}", self.current_pid, pid); let current_pid = self.current_pid; - self.get_mut(current_pid).status = Status::Sleeping(pid); + self.get_mut(current_pid).status = Status::Waiting(pid); WaitResult::Blocked } } fn find_waiter(&self, pid: Pid) -> Option { self.procs.values().find(|&p| { - p.status == Status::Sleeping(pid) || - (p.status == Status::Sleeping(0) && self.get(pid).parent == p.pid) + p.status == Status::Waiting(pid) || + (p.status == Status::Waiting(0) && self.get(pid).parent == p.pid) }).map(|ref p| p.pid) } } @@ -173,10 +212,23 @@ pub enum WaitTarget { pub enum WaitResult { /// The target process is still running. - /// The waiter's status will be set to `Sleeping`. + /// The waiter's status will be set to `Waiting`. Blocked, /// The target process is exited with `ErrorCode`. Ok(ErrorCode), /// The target process is not exist. NotExist, +} + +#[derive(Debug)] +enum Event { + Schedule, + Wakeup(Pid), +} + +impl GetMut2 for BTreeMap { + type Output = Process; + fn get_mut(&mut self, id: Pid) -> &mut Process { + self.get_mut(&id).unwrap() + } } \ No newline at end of file diff --git a/src/schedule.rs b/src/schedule.rs deleted file mode 100644 index 80bf63a..0000000 --- a/src/schedule.rs +++ /dev/null @@ -1,89 +0,0 @@ -use spin::Mutex; -use alloc::BinaryHeap; -use arch::interrupt::TrapFrame; -use core::cmp::{Ordering, PartialOrd}; - -pub fn get_time() -> i32 { - info!("get_time:"); - EVENT_HUB.get_time() as i32 -} - -pub fn timer_handler(tf: &TrapFrame, rsp: &mut usize) { - // Store rsp to global for `schedule` - *RSP.lock() = Some(*rsp); - - EVENT_HUB.tick(); - - // Take rsp from global - *rsp = RSP.lock().take().unwrap(); -} - -static RSP: Mutex> = Mutex::new(None); - -fn schedule() { - info!("Schedule at time {}", EVENT_HUB.get_time()); - use process; - process::schedule(RSP.lock().as_mut().unwrap()); - - // Repeat - EVENT_HUB.add(100, schedule); -} - -lazy_static! { - static ref EVENT_HUB: EventHub = { - let e = EventHub::default(); - e.add(100, schedule); - info!("EventHub: init"); - e - }; -} - -type Time = usize; -type TimerHandler = fn(); - -#[derive(Debug, Eq, PartialEq)] -struct Timer { - time: Time, - handler: TimerHandler, -} - -impl PartialOrd for Timer { - fn partial_cmp(&self, other: &Self) -> Option { - other.time.partial_cmp(&self.time) - } -} - -impl Ord for Timer { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(&other).unwrap() - } -} - -#[derive(Default)] -struct EventHub { - tick: Mutex