Separate ProcessManager to a mod.

master
WangRunji 6 years ago
parent f7eb09e856
commit 5db908b1c5

@ -12,8 +12,12 @@ extern crate spin;
#[macro_use]
extern crate std;
pub mod processor;
mod process_manager;
mod processor;
pub mod scheduler;
pub mod thread;
mod util;
mod event_hub;
pub use process_manager::*;
pub use processor::Processor;

@ -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,
}
}
}

@ -1,9 +1,8 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use alloc::sync::Arc;
use spin::Mutex;
use scheduler::Scheduler;
use core::cell::UnsafeCell;
use process_manager::*;
/// Process executor
///
@ -90,119 +89,3 @@ impl Processor {
}
}
}
struct Process {
id: Pid,
status: Status,
status_after_stop: Status,
context: Option<Box<Context>>,
}
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,
}
}
}

@ -28,12 +28,11 @@
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use core::any::Any;
use core::marker::PhantomData;
use core::ptr;
use core::time::Duration;
use core::ops::DerefMut;
use processor::*;
use process_manager::*;
use scheduler::Scheduler;
/// All dependencies for thread mod.

@ -2,7 +2,7 @@ use arch::interrupt::{TrapFrame, Context as ArchContext};
use memory::{MemoryArea, MemoryAttr, MemorySet};
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}};
use core::fmt::{Debug, Error, Formatter};
use ucore_process::processor::Context;
use ucore_process::Context;
use alloc::boxed::Box;
pub struct ContextImpl {

@ -1,8 +1,7 @@
use spin::Once;
use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq};
pub use self::context::ContextImpl;
pub use ucore_process::processor::*;
pub use ucore_process::scheduler::*;
pub use ucore_process::*;
pub use ucore_process::thread::*;
use alloc::boxed::Box;
use consts::MAX_CPU_NUM;
@ -14,7 +13,7 @@ mod context;
pub fn init() {
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass
let scheduler = Box::new(RRScheduler::new(5));
let scheduler = Box::new(scheduler::RRScheduler::new(5));
let manager = Arc::new(ProcessManager::new(scheduler));
extern fn idle(_arg: usize) -> ! {

Loading…
Cancel
Save