diff --git a/crate/process/Cargo.toml b/crate/process/Cargo.toml new file mode 100644 index 0000000..2a75b85 --- /dev/null +++ b/crate/process/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ucore-process" +version = "0.1.0" +authors = ["WangRunji "] + +[dependencies] +log = { git = "https://github.com/riscv-and-rust-and-decaf/log.git" } diff --git a/crate/process/src/event_hub.rs b/crate/process/src/event_hub.rs new file mode 100644 index 0000000..cf7fa19 --- /dev/null +++ b/crate/process/src/event_hub.rs @@ -0,0 +1,61 @@ +use alloc::BinaryHeap; +use core::cmp::{Ordering, PartialOrd}; + +type Time = usize; + +struct Timer { + time: Time, + data: T, +} + +impl PartialEq for Timer { + fn eq(&self, other: &Self) -> bool { + self.time.eq(&other.time) + } +} + +impl Eq for Timer {} + +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() + } +} + +pub struct EventHub { + tick: Time, + timers: BinaryHeap>, +} + +impl EventHub { + pub fn new() -> Self { + EventHub { + tick: 0, + timers: BinaryHeap::new(), + } + } + pub fn tick(&mut self) { + self.tick += 1; + } + pub fn pop(&mut self) -> Option { + match self.timers.peek() { + None => return None, + Some(timer) if timer.time != self.tick => return None, + _ => {} + }; + self.timers.pop().map(|t| t.data) + } + pub fn push(&mut self, time_after: Time, data: T) { + let time = self.tick + time_after; + self.timers.push(Timer { time, data }); + } + pub fn get_time(&self) -> Time { + self.tick + } +} \ No newline at end of file diff --git a/crate/process/src/lib.rs b/crate/process/src/lib.rs new file mode 100644 index 0000000..a9d1cea --- /dev/null +++ b/crate/process/src/lib.rs @@ -0,0 +1,19 @@ +#![no_std] +#![feature(alloc)] +#![feature(const_fn)] +#![feature(linkage)] +#![feature(universal_impl_trait, conservative_impl_trait)] + +extern crate alloc; +#[macro_use] +extern crate log; + +// To use `println!` in test +#[cfg(test)] +#[macro_use] +extern crate std; + +pub mod processor; +pub mod scheduler; +mod util; +mod event_hub; diff --git a/kernel/src/process/processor.rs b/crate/process/src/processor.rs similarity index 84% rename from kernel/src/process/processor.rs rename to crate/process/src/processor.rs index 903f846..2525bb8 100644 --- a/kernel/src/process/processor.rs +++ b/crate/process/src/processor.rs @@ -1,15 +1,15 @@ -use alloc::BTreeMap; -use core::fmt::{Debug, Error, Formatter}; -use super::context::*; -use super::scheduler::*; -use util::{EventHub, GetMut2}; +use alloc::{boxed::Box, BTreeMap}; +use scheduler::*; +use event_hub::EventHub; +use util::GetMut2; +use core::fmt::Debug; #[derive(Debug)] -pub struct Process { +pub struct Process { pid: Pid, parent: Pid, status: Status, - context: Context, + context: T, } pub type Pid = usize; @@ -24,17 +24,21 @@ pub enum Status { Exited(ErrorCode), } -pub struct Processor { - procs: BTreeMap, +pub trait Context: Debug { + unsafe fn switch(&mut self, target: &mut Self); +} + +pub struct Processor_ { + procs: BTreeMap>, current_pid: Pid, event_hub: EventHub, /// Choose what on next schedule ? next: Option, // WARNING: if MAX_PROCESS_NUM is too large, will cause stack overflow - scheduler: RRScheduler, + scheduler: S, } -impl Process { +impl Process { fn exit_code(&self) -> Option { match self.status { Status::Exited(code) => Some(code), @@ -44,30 +48,29 @@ impl Process { } // TODO: 除schedule()外的其它函数,应该只设置进程状态,不应调用schedule -impl Processor { - pub fn new(init_context: Context) -> Self { +impl Processor_ { + pub fn new(init_context: T, scheduler: S) -> Self { let init_proc = Process { pid: 0, parent: 0, status: Status::Running, context: init_context, }; - Processor { + Processor_ { procs: { - let mut map = BTreeMap::::new(); + let mut map = BTreeMap::>::new(); map.insert(0, init_proc); map }, current_pid: 0, event_hub: EventHub::new(), next: None, - // NOTE: max_time_slice <= 5 to ensure 'priority' test pass - scheduler: RRScheduler::new(5), + scheduler, } } - pub fn lab6_set_priority(&mut self, priority: u8) { -// self.scheduler.set_priority(self.current_pid, priority); + pub fn set_priority(&mut self, priority: u8) { + self.scheduler.set_priority(self.current_pid, priority); } pub fn set_reschedule(&mut self) { @@ -127,7 +130,7 @@ impl Processor { self.event_hub.get_time() } - pub fn add(&mut self, context: Context) -> Pid { + pub fn add(&mut self, context: T) -> Pid { let pid = self.alloc_pid(); let process = Process { pid, @@ -173,22 +176,16 @@ impl Processor { self.scheduler.remove(pid); info!("switch from {} to {} {:x?}", pid0, pid, to.context); - unsafe { - // FIXME: safely pass MutexGuard - use core::mem::forget; - super::PROCESSOR.try().unwrap().force_unlock(); - from.context.switch(&mut to.context); - forget(super::processor()); - } + unsafe { from.context.switch(&mut to.context); } } - fn get(&self, pid: Pid) -> &Process { + fn get(&self, pid: Pid) -> &Process { self.procs.get(&pid).unwrap() } - fn get_mut(&mut self, pid: Pid) -> &mut Process { + fn get_mut(&mut self, pid: Pid) -> &mut Process { self.procs.get_mut(&pid).unwrap() } - pub fn current_context(&self) -> &Context { + pub fn current_context(&self) -> &T { &self.get(self.current_pid).context } pub fn current_pid(&self) -> Pid { @@ -270,9 +267,9 @@ enum Event { Wakeup(Pid), } -impl GetMut2 for BTreeMap { - type Output = Process; - fn get_mut(&mut self, id: Pid) -> &mut Process { +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/kernel/src/process/scheduler.rs b/crate/process/src/scheduler.rs similarity index 95% rename from kernel/src/process/scheduler.rs rename to crate/process/src/scheduler.rs index 7bcb57a..234b7bc 100644 --- a/kernel/src/process/scheduler.rs +++ b/crate/process/src/scheduler.rs @@ -1,13 +1,15 @@ -use super::*; -use consts::MAX_PROCESS_NUM; use alloc::BinaryHeap; +type Pid = usize; +const MAX_PROCESS_NUM: usize = 32; + /// pub trait Scheduler { fn insert(&mut self, pid: Pid); fn remove(&mut self, pid: Pid); fn select(&mut self) -> Option; fn tick(&mut self, current: Pid) -> bool; // need reschedule? + fn set_priority(&mut self, pid: Pid, priority: u8); } pub use self::rr::RRScheduler; @@ -73,6 +75,9 @@ mod rr { } *rest == 0 } + + fn set_priority(&mut self, pid: usize, priority: u8) { + } } impl RRScheduler { @@ -177,6 +182,11 @@ mod stride { } *rest == 0 } + + fn set_priority(&mut self, pid: Pid, priority: u8) { + self.infos[pid].priority = priority; + debug!("{} priority = {}", pid, priority); + } } impl StrideScheduler { @@ -187,9 +197,5 @@ mod stride { queue: BinaryHeap::new(), } } - pub fn set_priority(&mut self, pid: Pid, priority: u8) { - self.infos[pid].priority = priority; - debug!("{} priority = {}", pid, priority); - } } } \ No newline at end of file diff --git a/crate/process/src/util.rs b/crate/process/src/util.rs new file mode 100644 index 0000000..11a8d3c --- /dev/null +++ b/crate/process/src/util.rs @@ -0,0 +1,15 @@ +use core::fmt::Debug; + +/// Get values by 2 diff keys at the same time +pub trait GetMut2 { + type Output; + fn get_mut(&mut self, id: Idx) -> &mut Self::Output; + fn get_mut2(&mut self, id1: Idx, id2: Idx) -> (&mut Self::Output, &mut Self::Output) { + assert_ne!(id1, id2); + let self1 = self as *mut Self; + let self2 = self1; + let p1 = unsafe { &mut *self1 }.get_mut(id1); + let p2 = unsafe { &mut *self2 }.get_mut(id2); + (p1, p2) + } +} diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 05aeeda..6e1746f 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -138,6 +138,7 @@ dependencies = [ "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ucore-memory 0.1.0", + "ucore-process 0.1.0", "volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -175,6 +176,13 @@ dependencies = [ name = "ucore-memory" version = "0.1.0" +[[package]] +name = "ucore-process" +version = "0.1.0" +dependencies = [ + "log 0.4.3 (git+https://github.com/riscv-and-rust-and-decaf/log.git)", +] + [[package]] name = "usize_conversions" version = "0.2.0" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 09bb658..9355b7c 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -36,6 +36,7 @@ volatile = "0.1.0" lazy_static = { version = "1.0.0", features = ["spin_no_std"] } bit-allocator = { path = "../crate/bit-allocator" } ucore-memory = { path = "../crate/memory" } +ucore-process = { path = "../crate/process" } simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" } [target.x86_64-blog_os.dependencies] diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 3a132a3..3682c25 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -40,6 +40,7 @@ extern crate compiler_builtins; extern crate simple_filesystem; extern crate spin; extern crate ucore_memory; +extern crate ucore_process; extern crate volatile; #[macro_use] #[cfg(target_arch = "x86_64")] diff --git a/kernel/src/process/context.rs b/kernel/src/process/context.rs index 5d82af8..aca7c7e 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/context.rs @@ -8,10 +8,16 @@ pub struct Context { memory_set: MemorySet, } -impl Context { - pub unsafe fn switch(&mut self, target: &mut Self) { +impl ::ucore_process::processor::Context for Context { + unsafe fn switch(&mut self, target: &mut Self) { + super::PROCESSOR.try().unwrap().force_unlock(); self.arch.switch(&mut target.arch); + use core::mem::forget; + forget(super::processor()); } +} + +impl Context { pub unsafe fn new_init() -> Self { Context { diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index bdef0da..61dc0de 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -1,16 +1,20 @@ -use alloc::String; -pub use self::context::*; -pub use self::processor::*; use spin::Once; use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq}; +pub use self::context::Context; +pub use ucore_process::processor::*; +pub use ucore_process::scheduler::*; mod context; -mod processor; -mod scheduler; + +type Processor = Processor_; pub fn init() { PROCESSOR.call_once(|| - SpinNoIrqLock::new(Processor::new(unsafe { Context::new_init() })) + SpinNoIrqLock::new(Processor::new( + unsafe { Context::new_init() }, + // NOTE: max_time_slice <= 5 to ensure 'priority' test pass + StrideScheduler::new(5), + )) ); } diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 60ab019..7fde98f 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -117,7 +117,7 @@ fn sys_get_time() -> i32 { fn sys_lab6_set_priority(priority: usize) -> i32 { let mut processor = processor(); - processor.lab6_set_priority(priority as u8); + processor.set_priority(priority as u8); 0 } diff --git a/kernel/src/util.rs b/kernel/src/util.rs index 4092e99..f8ad1a1 100644 --- a/kernel/src/util.rs +++ b/kernel/src/util.rs @@ -1,5 +1,4 @@ use core::fmt::Debug; -pub use self::event::EventHub; pub fn bytes_sum(p: &T) -> u8 { use core::mem::size_of_val; @@ -28,82 +27,3 @@ pub unsafe fn from_cstr(s: *const u8) -> &'static str { let len = (0usize..).find(|&i| *s.offset(i as isize) == 0).unwrap(); str::from_utf8(slice::from_raw_parts(s, len)).unwrap() } - -/// Get values by 2 diff keys at the same time -pub trait GetMut2 { - type Output; - fn get_mut(&mut self, id: Idx) -> &mut Self::Output; - fn get_mut2(&mut self, id1: Idx, id2: Idx) -> (&mut Self::Output, &mut Self::Output) { - assert_ne!(id1, id2); - let self1 = self as *mut Self; - let self2 = self1; - let p1 = unsafe { &mut *self1 }.get_mut(id1); - let p2 = unsafe { &mut *self2 }.get_mut(id2); - (p1, p2) - } -} - - -mod event { - use alloc::BinaryHeap; - use core::cmp::{Ordering, PartialOrd}; - - type Time = usize; - - struct Timer { - time: Time, - data: T, - } - - impl PartialEq for Timer { - fn eq(&self, other: &Self) -> bool { - self.time.eq(&other.time) - } - } - - impl Eq for Timer {} - - 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() - } - } - - pub struct EventHub { - tick: Time, - timers: BinaryHeap>, - } - - impl EventHub { - pub fn new() -> Self { - EventHub { - tick: 0, - timers: BinaryHeap::new(), - } - } - pub fn tick(&mut self) { - self.tick += 1; - } - pub fn pop(&mut self) -> Option { - match self.timers.peek() { - None => return None, - Some(timer) if timer.time != self.tick => return None, - _ => {} - }; - self.timers.pop().map(|t| t.data) - } - pub fn push(&mut self, time_after: Time, data: T) { - let time = self.tick + time_after; - self.timers.push(Timer { time, data }); - } - pub fn get_time(&self) -> Time { - self.tick - } - } -} \ No newline at end of file