Merge branch 'OsTrain2018-g4' of github.com:oscourse-tsinghua/RustOS into lcy_issue1

master
lcy1996 6 years ago
commit e6fa56ac28

@ -50,6 +50,13 @@ impl<T> Process<T> {
// TODO: 除schedule()外的其它函数应该只设置进程状态不应调用schedule // TODO: 除schedule()外的其它函数应该只设置进程状态不应调用schedule
impl<T: Context, S: Scheduler> Processor_<T, S> { impl<T: Context, S: Scheduler> Processor_<T, S> {
/*
** @brief create a new Processor
** @param init_context: T initiate context
** scheduler: S the scheduler to use
** @retval the Processor created
*/
pub fn new(init_context: T, scheduler: S) -> Self { pub fn new(init_context: T, scheduler: S) -> Self {
let init_proc = Process { let init_proc = Process {
pid: 0, pid: 0,
@ -70,15 +77,30 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
} }
} }
/*
** @brief set the priority of current process
** @param priority: u8 the priority to set
** @retval none
*/
pub fn set_priority(&mut self, priority: u8) { pub fn set_priority(&mut self, priority: u8) {
self.scheduler.set_priority(self.current_pid, priority); self.scheduler.set_priority(self.current_pid, priority);
} }
/*
** @brief mark the current process to reschedule
** @param none
** @retval none
*/
pub fn set_reschedule(&mut self) { pub fn set_reschedule(&mut self) {
let pid = self.current_pid; let pid = self.current_pid;
self.set_status(pid, Status::Ready); self.set_status(pid, Status::Ready);
} }
/*
** @brief allocate the pid of the process
** @param none
** @retval the pid allocated
*/
fn alloc_pid(&self) -> Pid { fn alloc_pid(&self) -> Pid {
let mut next: Pid = 0; let mut next: Pid = 0;
for &i in self.procs.keys() { for &i in self.procs.keys() {
@ -91,6 +113,12 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
return next; return next;
} }
/*
** @brief set the status of the process
** @param pid: Pid the pid of process which needs to be set
** status: Status the status to be set
** @retval none
*/
fn set_status(&mut self, pid: Pid, status: Status) { fn set_status(&mut self, pid: Pid, status: Status) {
let status0 = self.get(pid).status.clone(); let status0 = self.get(pid).status.clone();
match (&status0, &status) { match (&status0, &status) {
@ -103,8 +131,12 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
self.get_mut(pid).status = status; self.get_mut(pid).status = status;
} }
/// Called by timer. /*
/// Handle events. ** @brief Called by timer.
** Handle events.
** @param none
** @retval none
*/
pub fn tick(&mut self) { pub fn tick(&mut self) {
let current_pid = self.current_pid; let current_pid = self.current_pid;
if self.scheduler.tick(current_pid) { if self.scheduler.tick(current_pid) {
@ -127,10 +159,20 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
} }
} }
/*
** @brief get now time
** @param none
** @retval the time got
*/
pub fn get_time(&self) -> usize { pub fn get_time(&self) -> usize {
self.event_hub.get_time() self.event_hub.get_time()
} }
/*
** @brief add a new process
** @param context: T the context fo the process
** @retval the pid of new process
*/
pub fn add(&mut self, context: T) -> Pid { pub fn add(&mut self, context: T) -> Pid {
let pid = self.alloc_pid(); let pid = self.alloc_pid();
let process = Process { let process = Process {
@ -144,8 +186,12 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
pid pid
} }
/// Called every interrupt end /*
/// Do schedule ONLY IF current status != Running ** @brief Called every interrupt end
** Do schedule ONLY IF current status != Running
** @param none
** @retval none
*/
pub fn schedule(&mut self) { pub fn schedule(&mut self) {
if self.get(self.current_pid).status == Status::Running { if self.get(self.current_pid).status == Status::Running {
return; return;
@ -154,9 +200,13 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
self.switch_to(pid); self.switch_to(pid);
} }
/// Switch process to `pid`, switch page table if necessary. /*
/// Store `rsp` and point it to target kernel stack. ** @brief Switch process to `pid`, switch page table if necessary.
/// The current status must be set before, and not be `Running`. Store `rsp` and point it to target kernel stack.
The current status must be set before, and not be `Running`.
** @param the pid of the process to switch
** @retval none
*/
fn switch_to(&mut self, pid: Pid) { fn switch_to(&mut self, pid: Pid) {
// for debug print // for debug print
let pid0 = self.current_pid; let pid0 = self.current_pid;
@ -180,23 +230,57 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
unsafe { from.context.switch(&mut to.context); } unsafe { from.context.switch(&mut to.context); }
} }
/*
** @brief get process by pid
** @param pid: Pid the pid of the process
** @retval the process struct
*/
fn get(&self, pid: Pid) -> &Process<T> { fn get(&self, pid: Pid) -> &Process<T> {
self.procs.get(&pid).unwrap() self.procs.get(&pid).unwrap()
} }
/*
** @brief get mut process struct by pid
** @param pid: Pid the pid of the process
** @retval the mut process struct
*/
fn get_mut(&mut self, pid: Pid) -> &mut Process<T> { fn get_mut(&mut self, pid: Pid) -> &mut Process<T> {
self.procs.get_mut(&pid).unwrap() self.procs.get_mut(&pid).unwrap()
} }
/*
** @brief get context of current process
** @param none
** @retval current context
*/
pub fn current_context(&self) -> &T { pub fn current_context(&self) -> &T {
&self.get(self.current_pid).context &self.get(self.current_pid).context
} }
/*
** @brief get pid of current process
** @param none
** @retval current pid
*/
pub fn current_pid(&self) -> Pid { pub fn current_pid(&self) -> Pid {
self.current_pid self.current_pid
} }
/*
** @brief kill a process by pid
** @param pid: Pid the pid of the process to kill
** @retval none
*/
pub fn kill(&mut self, pid: Pid) { pub fn kill(&mut self, pid: Pid) {
self.exit(pid, 0x1000); // TODO: error code for killed self.exit(pid, 0x1000); // TODO: error code for killed
} }
/*
** @brief exit a process by pid
** @param pid: Pid the pid to exit
** error_code: ErrorCode the error code when exiting
** @retval none
*/
pub fn exit(&mut self, pid: Pid, error_code: ErrorCode) { pub fn exit(&mut self, pid: Pid, error_code: ErrorCode) {
info!("{} exit, code: {}", pid, error_code); info!("{} exit, code: {}", pid, error_code);
self.set_status(pid, Status::Exited(error_code)); self.set_status(pid, Status::Exited(error_code));
@ -207,18 +291,40 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
} }
} }
/*
** @brief let a process to sleep for a while
** @param pid: Pid the pid of the process to sleep
** time: usize the time to sleep
** @retval none
*/
pub fn sleep(&mut self, pid: Pid, time: usize) { pub fn sleep(&mut self, pid: Pid, time: usize) {
self.set_status(pid, Status::Sleeping); self.set_status(pid, Status::Sleeping);
self.event_hub.push(time, Event::Wakeup(pid)); self.event_hub.push(time, Event::Wakeup(pid));
} }
/*
** @brief let a process to sleep until wake up
** @param pid: Pid the pid of the process to sleep
** @retval none
*/
pub fn sleep_(&mut self, pid: Pid) { pub fn sleep_(&mut self, pid: Pid) {
self.set_status(pid, Status::Sleeping); self.set_status(pid, Status::Sleeping);
} }
/*
** @brief wake up al sleeping process
** @param pid: Pid the pid of the process to wake up
** @retval none
*/
pub fn wakeup_(&mut self, pid: Pid) { pub fn wakeup_(&mut self, pid: Pid) {
self.set_status(pid, Status::Ready); self.set_status(pid, Status::Ready);
} }
/// Let current process wait for another /*
** @brief Let current process wait for another
** @param pid: Pid the pid of the process to wait for
** @retval the result of wait
*/
pub fn current_wait_for(&mut self, pid: Pid) -> WaitResult { pub fn current_wait_for(&mut self, pid: Pid) -> WaitResult {
info!("current {} wait for {:?}", self.current_pid, pid); info!("current {} wait for {:?}", self.current_pid, pid);
if self.procs.values().filter(|&p| p.parent == self.current_pid).next().is_none() { if self.procs.values().filter(|&p| p.parent == self.current_pid).next().is_none() {
@ -236,7 +342,11 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
WaitResult::Ok(pid, exit_code) WaitResult::Ok(pid, exit_code)
} }
/// Try to find a exited wait target /*
** @brief Try to find a exited wait target
** @param pid: Pid the pid of the process to wait for
** @retval the pid found or none
*/
fn try_wait(&mut self, pid: Pid) -> Option<Pid> { fn try_wait(&mut self, pid: Pid) -> Option<Pid> {
match pid { match pid {
0 => self.procs.values() 0 => self.procs.values()
@ -246,6 +356,11 @@ impl<T: Context, S: Scheduler> Processor_<T, S> {
} }
} }
/*
** @brief find one process which is waiting for the input process
** @param pid: Pid the pid of the target process
** @retval the pid of the waiting process or none
*/
fn find_waiter(&self, pid: Pid) -> Option<Pid> { fn find_waiter(&self, pid: Pid) -> Option<Pid> {
self.procs.values().find(|&p| { self.procs.values().find(|&p| {
p.status == Status::Waiting(pid) || p.status == Status::Waiting(pid) ||

@ -2,18 +2,51 @@ use alloc::{collections::BinaryHeap, vec::Vec};
type Pid = usize; type Pid = usize;
///
// implements of process scheduler
pub trait Scheduler { pub trait Scheduler {
/*
** @brief add a new process
** @param pid: Pid the pid of the process to add
** @retval none
*/
fn insert(&mut self, pid: Pid); fn insert(&mut self, pid: Pid);
/*
** @brief remove a processs from the list
** @param pid: Pid the pid of the process to remove
** @retval none
*/
fn remove(&mut self, pid: Pid); fn remove(&mut self, pid: Pid);
/*
** @brief choose a process to run next
** @param none
** @retval Option<Pid> the pid of the process to run or none
*/
fn select(&mut self) -> Option<Pid>; fn select(&mut self) -> Option<Pid>;
/*
** @brief when a clock interrupt occurs, update the list and check whether need to reschedule
** @param current: Pid the pid of the process which is running now
** @retval bool if need to reschedule
*/
fn tick(&mut self, current: Pid) -> bool; // need reschedule? fn tick(&mut self, current: Pid) -> bool; // need reschedule?
/*
** @brief set the priority of the process
** @param pid: Pid the pid of the process to be set
** priority: u8 the priority to be set
** @retval none
*/
fn set_priority(&mut self, pid: Pid, priority: u8); fn set_priority(&mut self, pid: Pid, priority: u8);
} }
pub use self::rr::RRScheduler; pub use self::rr::RRScheduler;
pub use self::stride::StrideScheduler; pub use self::stride::StrideScheduler;
// use round-robin scheduling
mod rr { mod rr {
use super::*; use super::*;
@ -106,6 +139,7 @@ mod rr {
} }
} }
// use stride scheduling
mod stride { mod stride {
use super::*; use super::*;

@ -50,7 +50,11 @@ pub struct ThreadMod<S: ThreadSupport> {
} }
impl<S: ThreadSupport> ThreadMod<S> { impl<S: ThreadSupport> ThreadMod<S> {
/// Gets a handle to the thread that invokes it. /*
** @brief Gets a handle to the thread that invokes it.
** @param none
** @retval the thread to get
*/
pub fn current() -> Thread<S> { pub fn current() -> Thread<S> {
Thread { Thread {
pid: S::processor().current_pid(), pid: S::processor().current_pid(),
@ -58,7 +62,11 @@ impl<S: ThreadSupport> ThreadMod<S> {
} }
} }
/// Puts the current thread to sleep for the specified amount of time. /*
** @brief Puts the current thread to sleep for the specified amount of time.
** @param dur: Duration the time to sleep
** @retval none
*/
pub fn sleep(dur: Duration) { pub fn sleep(dur: Duration) {
let time = dur_to_ticks(dur); let time = dur_to_ticks(dur);
info!("sleep: {:?} ticks", time); info!("sleep: {:?} ticks", time);
@ -72,7 +80,11 @@ impl<S: ThreadSupport> ThreadMod<S> {
} }
} }
/// Spawns a new thread, returning a JoinHandle for it. /*
** @brief Spawns a new thread, returning a JoinHandle for it.
** @param f: F the thread to start
** @retval JoinHandle the JoinHandle of the new thread
*/
pub fn spawn<F, T>(f: F) -> JoinHandle<S, T> pub fn spawn<F, T>(f: F) -> JoinHandle<S, T>
where where
F: Send + 'static + FnOnce() -> T, F: Send + 'static + FnOnce() -> T,
@ -103,7 +115,11 @@ impl<S: ThreadSupport> ThreadMod<S> {
} }
} }
/// Cooperatively gives up a timeslice to the OS scheduler. /*
** @brief Cooperatively gives up a timeslice to the OS scheduler.
** @param none
** @retval none
*/
pub fn yield_now() { pub fn yield_now() {
info!("yield:"); info!("yield:");
let mut processor = S::processor(); let mut processor = S::processor();
@ -111,7 +127,11 @@ impl<S: ThreadSupport> ThreadMod<S> {
processor.schedule(); processor.schedule();
} }
/// Blocks unless or until the current thread's token is made available. /*
** @brief Blocks unless or until the current thread's token is made available.
** @param none
** @retval none
*/
pub fn park() { pub fn park() {
info!("park:"); info!("park:");
let mut processor = S::processor(); let mut processor = S::processor();
@ -128,12 +148,20 @@ pub struct Thread<S: ThreadSupport> {
} }
impl<S: ThreadSupport> Thread<S> { impl<S: ThreadSupport> Thread<S> {
/// Atomically makes the handle's token available if it is not already. /*
** @brief Atomically makes the handle's token available if it is not already.
** @param none
** @retval none
*/
pub fn unpark(&self) { pub fn unpark(&self) {
let mut processor = S::processor(); let mut processor = S::processor();
processor.wakeup_(self.pid); processor.wakeup_(self.pid);
} }
/// Gets the thread's unique identifier. /*
** @brief Gets the thread's unique identifier.
** @param none
** @retval usize the the thread's unique identifier
*/
pub fn id(&self) -> usize { pub fn id(&self) -> usize {
self.pid self.pid
} }
@ -146,11 +174,19 @@ pub struct JoinHandle<S: ThreadSupport, T> {
} }
impl<S: ThreadSupport, T> JoinHandle<S, T> { impl<S: ThreadSupport, T> JoinHandle<S, T> {
/// Extracts a handle to the underlying thread. /*
** @brief Extracts a handle to the underlying thread.
** @param none
** @retval the thread of the handle
*/
pub fn thread(&self) -> &Thread<S> { pub fn thread(&self) -> &Thread<S> {
&self.thread &self.thread
} }
/// Waits for the associated thread to finish. /*
** @brief Waits for the associated thread to finish.
** @param none
** @retval Result<T, ()> the result of the associated thread
*/
pub fn join(self) -> Result<T, ()> { pub fn join(self) -> Result<T, ()> {
let mut processor = S::processor(); let mut processor = S::processor();
match processor.current_wait_for(self.thread.pid) { match processor.current_wait_for(self.thread.pid) {

Loading…
Cancel
Save