parent
							
								
									f7eb09e856
								
							
						
					
					
						commit
						5db908b1c5
					
				| @ -0,0 +1,120 @@ | |||||||
|  | use alloc::boxed::Box; | ||||||
|  | use alloc::sync::Arc; | ||||||
|  | use spin::Mutex; | ||||||
|  | use scheduler::Scheduler; | ||||||
|  | use core::cell::UnsafeCell; | ||||||
|  | 
 | ||||||
|  | struct Process { | ||||||
|  |     id: Pid, | ||||||
|  |     status: Status, | ||||||
|  |     status_after_stop: Status, | ||||||
|  |     context: Option<Box<Context>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub type Pid = usize; | ||||||
|  | type ExitCode = usize; | ||||||
|  | const MAX_PROC_NUM: usize = 32; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Clone, Eq, PartialEq)] | ||||||
|  | pub enum Status { | ||||||
|  |     Ready, | ||||||
|  |     Running(usize), | ||||||
|  |     Waiting(Pid), | ||||||
|  |     Sleeping, | ||||||
|  |     Exited(ExitCode), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub trait Context { | ||||||
|  |     unsafe fn switch_to(&mut self, target: &mut Context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct ProcessManager { | ||||||
|  |     procs: [Mutex<Option<Process>>; MAX_PROC_NUM], | ||||||
|  |     scheduler: Mutex<Box<Scheduler>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ProcessManager { | ||||||
|  |     pub fn new(scheduler: Box<Scheduler>) -> Self { | ||||||
|  |         ProcessManager { | ||||||
|  |             procs: Default::default(), | ||||||
|  |             scheduler: Mutex::new(scheduler), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn alloc_pid(&self) -> Pid { | ||||||
|  |         for i in 0..MAX_PROC_NUM { | ||||||
|  |             if self.procs[i].lock().is_none() { | ||||||
|  |                 return i; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         panic!("Process number exceeded"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Add a new process
 | ||||||
|  |     pub fn add(&self, context: Box<Context>) -> Pid { | ||||||
|  |         let pid = self.alloc_pid(); | ||||||
|  |         // TODO: check parent
 | ||||||
|  |         *self.procs[pid].lock() = Some(Process { | ||||||
|  |             id: pid, | ||||||
|  |             status: Status::Ready, | ||||||
|  |             status_after_stop: Status::Ready, | ||||||
|  |             context: Some(context), | ||||||
|  |         }); | ||||||
|  |         self.scheduler.lock().insert(pid); | ||||||
|  |         pid | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Make process `pid` time slice -= 1.
 | ||||||
|  |     /// Return true if time slice == 0.
 | ||||||
|  |     /// Called by timer interrupt handler.
 | ||||||
|  |     pub fn tick(&self, pid: Pid) -> bool { | ||||||
|  |         self.scheduler.lock().tick(pid) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Called by Processor to get a process to run.
 | ||||||
|  |     /// The manager first mark it `Running`,
 | ||||||
|  |     /// then take out and return its Context.
 | ||||||
|  |     pub fn run(&self, cpu_id: usize) -> (Pid, Box<Context>) { | ||||||
|  |         let mut scheduler = self.scheduler.lock(); | ||||||
|  |         let pid = scheduler.select() | ||||||
|  |             .expect("failed to select a runnable process"); | ||||||
|  |         scheduler.remove(pid); | ||||||
|  |         let mut proc_lock = self.procs[pid].lock(); | ||||||
|  |         let mut proc = proc_lock.as_mut().unwrap(); | ||||||
|  |         proc.status = Status::Running(cpu_id); | ||||||
|  |         (pid, proc.context.take().unwrap()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Called by Processor to finish running a process
 | ||||||
|  |     /// and give its context back.
 | ||||||
|  |     pub fn stop(&self, pid: Pid, context: Box<Context>) { | ||||||
|  |         let mut proc_lock = self.procs[pid].lock(); | ||||||
|  |         let mut proc = proc_lock.as_mut().unwrap(); | ||||||
|  |         proc.status = proc.status_after_stop.clone(); | ||||||
|  |         proc.status_after_stop = Status::Ready; | ||||||
|  |         proc.context = Some(context); | ||||||
|  |         if proc.status == Status::Ready { | ||||||
|  |             self.scheduler.lock().insert(pid); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Switch the status of a process.
 | ||||||
|  |     /// Insert/Remove it to/from scheduler if necessary.
 | ||||||
|  |     pub fn set_status(&self, pid: Pid, status: Status) { | ||||||
|  |         let mut scheduler = self.scheduler.lock(); | ||||||
|  |         let mut proc_lock = self.procs[pid].lock(); | ||||||
|  |         let mut proc = proc_lock.as_mut().unwrap(); | ||||||
|  |         match (&proc.status, &status) { | ||||||
|  |             (Status::Ready, Status::Ready) => return, | ||||||
|  |             (Status::Ready, _) => scheduler.remove(pid), | ||||||
|  |             (Status::Running(_), _) => {}, | ||||||
|  |             (_, Status::Ready) => scheduler.insert(pid), | ||||||
|  |             _ => {} | ||||||
|  |         } | ||||||
|  |         trace!("process {} {:?} -> {:?}", pid, proc.status, status); | ||||||
|  |         match proc.status { | ||||||
|  |             Status::Running(_) => proc.status_after_stop = status, | ||||||
|  |             _ => proc.status = status, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
					Loading…
					
					
				
		Reference in new issue