mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 08:06:17 +04:00
simplify ProcessManager
- given that a proc can only be waited by its parent, wait_queue is no longer needed.
This commit is contained in:
parent
5478b9ba7b
commit
df485d506e
@ -11,6 +11,8 @@ struct Process {
|
|||||||
status: Status,
|
status: Status,
|
||||||
status_after_stop: Status,
|
status_after_stop: Status,
|
||||||
context: Option<Box<Context>>,
|
context: Option<Box<Context>>,
|
||||||
|
parent: Pid,
|
||||||
|
children: Vec<Pid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Pid = usize;
|
pub type Pid = usize;
|
||||||
@ -29,8 +31,8 @@ pub enum Status {
|
|||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
enum Event {
|
enum Event {
|
||||||
Wakeup(Pid),
|
Wakeup(Pid),
|
||||||
Dropped,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Context {
|
pub trait Context {
|
||||||
unsafe fn switch_to(&mut self, target: &mut Context);
|
unsafe fn switch_to(&mut self, target: &mut Context);
|
||||||
}
|
}
|
||||||
@ -38,8 +40,6 @@ pub trait Context {
|
|||||||
pub struct ProcessManager {
|
pub struct ProcessManager {
|
||||||
procs: Vec<Mutex<Option<Process>>>,
|
procs: Vec<Mutex<Option<Process>>>,
|
||||||
scheduler: Mutex<Box<Scheduler>>,
|
scheduler: Mutex<Box<Scheduler>>,
|
||||||
wait_queue: Vec<Mutex<Vec<Pid>>>,
|
|
||||||
children: Vec<Mutex<Vec<Pid>>>,
|
|
||||||
event_hub: Mutex<EventHub<Event>>,
|
event_hub: Mutex<EventHub<Event>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,39 +48,33 @@ impl ProcessManager {
|
|||||||
ProcessManager {
|
ProcessManager {
|
||||||
procs: new_vec_default(max_proc_num),
|
procs: new_vec_default(max_proc_num),
|
||||||
scheduler: Mutex::new(scheduler),
|
scheduler: Mutex::new(scheduler),
|
||||||
wait_queue: new_vec_default(max_proc_num),
|
|
||||||
children: new_vec_default(max_proc_num),
|
|
||||||
event_hub: Mutex::new(EventHub::new()),
|
event_hub: Mutex::new(EventHub::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_pid(&self) -> Pid {
|
fn alloc_pid(&self) -> Pid {
|
||||||
for (i, proc) in self.procs.iter().enumerate() {
|
for (i, proc) in self.procs.iter().enumerate() {
|
||||||
let mut proc_lock = proc.lock();
|
if proc.lock().is_none() {
|
||||||
if proc_lock.is_none() {
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
match proc_lock.as_mut().unwrap().status {
|
|
||||||
Status::Exited(_) => if self.wait_queue[i].lock().is_empty() {
|
|
||||||
*proc_lock = None;
|
|
||||||
return i;
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
panic!("Process number exceeded");
|
panic!("Process number exceeded");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a new process
|
/// Add a new process
|
||||||
pub fn add(&self, context: Box<Context>) -> Pid {
|
pub fn add(&self, context: Box<Context>, parent: Pid) -> Pid {
|
||||||
let pid = self.alloc_pid();
|
let pid = self.alloc_pid();
|
||||||
*(&self.procs[pid]).lock() = Some(Process {
|
*(&self.procs[pid]).lock() = Some(Process {
|
||||||
id: pid,
|
id: pid,
|
||||||
status: Status::Ready,
|
status: Status::Ready,
|
||||||
status_after_stop: Status::Ready,
|
status_after_stop: Status::Ready,
|
||||||
context: Some(context),
|
context: Some(context),
|
||||||
|
parent,
|
||||||
|
children: Vec::new(),
|
||||||
});
|
});
|
||||||
self.scheduler.lock().insert(pid);
|
self.scheduler.lock().insert(pid);
|
||||||
|
self.procs[parent].lock().as_mut().expect("invalid parent proc")
|
||||||
|
.children.push(pid);
|
||||||
pid
|
pid
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +87,6 @@ impl ProcessManager {
|
|||||||
while let Some(event) = event_hub.pop() {
|
while let Some(event) = event_hub.pop() {
|
||||||
match event {
|
match event {
|
||||||
Event::Wakeup(pid) => self.set_status(pid, Status::Ready),
|
Event::Wakeup(pid) => self.set_status(pid, Status::Ready),
|
||||||
Event::Dropped => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.scheduler.lock().tick(pid)
|
self.scheduler.lock().tick(pid)
|
||||||
@ -113,7 +106,7 @@ impl ProcessManager {
|
|||||||
.expect("failed to select a runnable process");
|
.expect("failed to select a runnable process");
|
||||||
scheduler.remove(pid);
|
scheduler.remove(pid);
|
||||||
let mut proc_lock = self.procs[pid].lock();
|
let mut proc_lock = self.procs[pid].lock();
|
||||||
let mut proc = proc_lock.as_mut().expect("process not exist");;
|
let mut proc = proc_lock.as_mut().expect("process not exist");
|
||||||
proc.status = Status::Running(cpu_id);
|
proc.status = Status::Running(cpu_id);
|
||||||
(pid, proc.context.take().expect("context not exist"))
|
(pid, proc.context.take().expect("context not exist"))
|
||||||
}
|
}
|
||||||
@ -136,19 +129,15 @@ impl ProcessManager {
|
|||||||
/// Switch the status of a process.
|
/// Switch the status of a process.
|
||||||
/// Insert/Remove it to/from scheduler if necessary.
|
/// Insert/Remove it to/from scheduler if necessary.
|
||||||
fn set_status(&self, pid: Pid, status: Status) {
|
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_lock = self.procs[pid].lock();
|
||||||
let mut proc = proc_lock.as_mut().expect("process not exist");
|
let mut proc = proc_lock.as_mut().expect("process not exist");
|
||||||
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
|
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
|
||||||
match (&proc.status, &status) {
|
match (&proc.status, &status) {
|
||||||
(Status::Ready, Status::Ready) => return,
|
(Status::Ready, Status::Ready) => return,
|
||||||
(Status::Ready, _) => scheduler.remove(pid),
|
(Status::Ready, _) => self.scheduler.lock().remove(pid),
|
||||||
(Status::Running(_), _) => {},
|
|
||||||
(Status::Exited(_), _) => panic!("can not set status for a exited process"),
|
(Status::Exited(_), _) => panic!("can not set status for a exited process"),
|
||||||
(Status::Waiting(target), Status::Exited(_)) =>
|
|
||||||
self.wait_queue[*target].lock().retain(|&i| i != pid),
|
|
||||||
(Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(pid)),
|
(Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(pid)),
|
||||||
(_, Status::Ready) => scheduler.insert(pid),
|
(_, Status::Ready) => self.scheduler.lock().insert(pid),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
match proc.status {
|
match proc.status {
|
||||||
@ -161,34 +150,34 @@ impl ProcessManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn get_status(&self, pid: Pid) -> Option<Status> {
|
pub fn get_status(&self, pid: Pid) -> Option<Status> {
|
||||||
let mut proc_lock = self.procs[pid].lock();
|
self.procs[pid].lock().as_ref().map(|p| p.status.clone())
|
||||||
if proc_lock.is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
match proc_lock.as_ref().unwrap().status {
|
|
||||||
Status::Exited(_) => if self.wait_queue[pid].lock().is_empty() {
|
|
||||||
*proc_lock = None;
|
|
||||||
return None;
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
proc_lock.as_ref().map(|p| p.status.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_done(&self, pid: Pid, target: Pid) {
|
/// Remove an exited proc `pid`.
|
||||||
let mut proc_lock = self.procs[target].lock();
|
/// Its all children will be set parent to 0.
|
||||||
|
pub fn remove(&self, pid: Pid) {
|
||||||
|
let mut proc_lock = self.procs[pid].lock();
|
||||||
let proc = proc_lock.as_ref().expect("process not exist");
|
let proc = proc_lock.as_ref().expect("process not exist");
|
||||||
match proc.status {
|
match proc.status {
|
||||||
Status::Exited(_) => self.del_child(pid, target),
|
Status::Exited(_) => {}
|
||||||
_ => panic!("can not remove non-exited process"),
|
_ => panic!("can not remove non-exited process"),
|
||||||
}
|
}
|
||||||
|
// orphan procs
|
||||||
|
for child in proc.children.iter() {
|
||||||
|
(&self.procs[*child]).lock().as_mut().expect("process not exist").parent = 0;
|
||||||
|
}
|
||||||
|
// remove self from parent's children list
|
||||||
|
self.procs[proc.parent].lock().as_mut().expect("process not exist")
|
||||||
|
.children.retain(|&i| i != pid);
|
||||||
|
// release the pid
|
||||||
|
*proc_lock = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sleep(&self, pid: Pid, time_raw: usize) {
|
/// Sleep `pid` for `time` ticks.
|
||||||
|
/// `time` == 0 means sleep forever
|
||||||
|
pub fn sleep(&self, pid: Pid, time: usize) {
|
||||||
self.set_status(pid, Status::Sleeping);
|
self.set_status(pid, Status::Sleeping);
|
||||||
let time = if time_raw >= (1 << 31) {0} else {time_raw};
|
|
||||||
if time != 0 {
|
if time != 0 {
|
||||||
self.event_hub.lock().push(time, Event::Wakeup(pid));
|
self.event_hub.lock().push(time, Event::Wakeup(pid));
|
||||||
}
|
}
|
||||||
@ -200,35 +189,28 @@ impl ProcessManager {
|
|||||||
|
|
||||||
pub fn wait(&self, pid: Pid, target: Pid) {
|
pub fn wait(&self, pid: Pid, target: Pid) {
|
||||||
self.set_status(pid, Status::Waiting(target));
|
self.set_status(pid, Status::Waiting(target));
|
||||||
self.wait_queue[target].lock().push(pid);
|
|
||||||
}
|
}
|
||||||
pub fn wait_child(&self, pid: Pid) {
|
pub fn wait_child(&self, pid: Pid) {
|
||||||
self.set_status(pid, Status::Waiting(0));
|
self.set_status(pid, Status::Waiting(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_parent(&self, pid: Pid, target: Pid) {
|
pub fn get_children(&self, pid: Pid) -> Vec<Pid> {
|
||||||
self.wait_queue[target].lock().push(pid);
|
self.procs[pid].lock().as_ref().expect("process not exist").children.clone()
|
||||||
self.children[pid].lock().push(target);
|
|
||||||
}
|
|
||||||
pub fn del_child(&self, pid: Pid, target: Pid) {
|
|
||||||
self.wait_queue[target].lock().retain(|&i| i != pid);
|
|
||||||
self.children[pid].lock().retain(|&i| i != target);
|
|
||||||
}
|
|
||||||
pub fn get_children(&self, pid: Pid) -> Vec<Pid>{
|
|
||||||
self.children[pid].lock().clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(&self, pid: Pid, code: ExitCode) {
|
pub fn exit(&self, pid: Pid, code: ExitCode) {
|
||||||
for child in self.children[pid].lock().drain(..) {
|
// NOTE: if `pid` is running, status change will be deferred.
|
||||||
self.wait_queue[child].lock().retain(|&i| i != pid);
|
|
||||||
}
|
|
||||||
self.set_status(pid, Status::Exited(code));
|
self.set_status(pid, Status::Exited(code));
|
||||||
}
|
}
|
||||||
/// Called when a process exit
|
/// Called when a process exit
|
||||||
fn exit_handler(&self, pid: Pid, proc: &mut Process) {
|
fn exit_handler(&self, pid: Pid, proc: &mut Process) {
|
||||||
for waiter in self.wait_queue[pid].lock().iter() {
|
// wakeup parent if waiting
|
||||||
self.wakeup(*waiter);
|
let parent = proc.parent;
|
||||||
|
match self.get_status(parent).expect("process not exist") {
|
||||||
|
Status::Waiting(target) if target == pid || target == 0 => self.wakeup(parent),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
// drop its context
|
||||||
proc.context = None;
|
proc.context = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
|
|||||||
|
|
||||||
// 在Processor中创建新的线程
|
// 在Processor中创建新的线程
|
||||||
let context = new_kernel_context(kernel_thread_entry::<F, T>, f as usize);
|
let context = new_kernel_context(kernel_thread_entry::<F, T>, f as usize);
|
||||||
let pid = processor().manager().add(context);
|
let pid = processor().manager().add(context, 0);
|
||||||
processor().manager().set_parent(0, pid);
|
|
||||||
|
|
||||||
// 接下来看看`JoinHandle::join()`的实现
|
// 接下来看看`JoinHandle::join()`的实现
|
||||||
// 了解是如何获取f返回值的
|
// 了解是如何获取f返回值的
|
||||||
@ -151,7 +150,7 @@ impl<T> JoinHandle<T> {
|
|||||||
trace!("{} join", self.thread.pid);
|
trace!("{} join", self.thread.pid);
|
||||||
match processor().manager().get_status(self.thread.pid) {
|
match processor().manager().get_status(self.thread.pid) {
|
||||||
Some(Status::Exited(exit_code)) => {
|
Some(Status::Exited(exit_code)) => {
|
||||||
processor().manager().wait_done(current().id(), self.thread.pid);
|
processor().manager().remove(self.thread.pid);
|
||||||
// Find return value on the heap from the exit code.
|
// Find return value on the heap from the exit code.
|
||||||
return Ok(unsafe { *Box::from_raw(exit_code as *mut T) });
|
return Ok(unsafe { *Box::from_raw(exit_code as *mut T) });
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ pub fn init() {
|
|||||||
loop { cpu::halt(); }
|
loop { cpu::halt(); }
|
||||||
}
|
}
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
manager.add(ContextImpl::new_kernel(idle, i));
|
manager.add(ContextImpl::new_kernel(idle, i), 0);
|
||||||
}
|
}
|
||||||
::shell::run_user_shell();
|
::shell::run_user_shell();
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use process::*;
|
|||||||
pub fn run_user_shell() {
|
pub fn run_user_shell() {
|
||||||
let inode = ROOT_INODE.lookup("sh").unwrap();
|
let inode = ROOT_INODE.lookup("sh").unwrap();
|
||||||
let data = inode.read_as_vec().unwrap();
|
let data = inode.read_as_vec().unwrap();
|
||||||
processor().manager().add(ContextImpl::new_user(data.as_slice(), "sh".split(' ')));
|
processor().manager().add(ContextImpl::new_user(data.as_slice(), "sh".split(' ')), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shell() {
|
pub fn shell() {
|
||||||
@ -24,7 +24,7 @@ pub fn shell() {
|
|||||||
let name = cmd.split(' ').next().unwrap();
|
let name = cmd.split(' ').next().unwrap();
|
||||||
if let Ok(file) = ROOT_INODE.lookup(name) {
|
if let Ok(file) = ROOT_INODE.lookup(name) {
|
||||||
let data = file.read_as_vec().unwrap();
|
let data = file.read_as_vec().unwrap();
|
||||||
let pid = processor().manager().add(ContextImpl::new_user(data.as_slice(), cmd.split(' ')));
|
let pid = processor().manager().add(ContextImpl::new_user(data.as_slice(), cmd.split(' ')), thread::current().id());
|
||||||
unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
|
unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
|
||||||
} else {
|
} else {
|
||||||
println!("Program not exist");
|
println!("Program not exist");
|
||||||
|
@ -143,8 +143,7 @@ fn sys_dup(fd1: usize, fd2: usize) -> SysResult {
|
|||||||
fn sys_fork(tf: &TrapFrame) -> SysResult {
|
fn sys_fork(tf: &TrapFrame) -> SysResult {
|
||||||
let mut context = process().fork(tf);
|
let mut context = process().fork(tf);
|
||||||
//memory_set_map_swappable(context.get_memory_set_mut());
|
//memory_set_map_swappable(context.get_memory_set_mut());
|
||||||
let pid = processor().manager().add(context);
|
let pid = processor().manager().add(context, thread::current().id());
|
||||||
processor().manager().set_parent(thread::current().id(), pid);
|
|
||||||
//memory_set_map_swappable(processor.get_context_mut(pid).get_memory_set_mut());
|
//memory_set_map_swappable(processor.get_context_mut(pid).get_memory_set_mut());
|
||||||
info!("fork: {} -> {}", thread::current().id(), pid);
|
info!("fork: {} -> {}", thread::current().id(), pid);
|
||||||
Ok(pid as i32)
|
Ok(pid as i32)
|
||||||
@ -168,7 +167,7 @@ fn sys_wait(pid: usize, code: *mut i32) -> SysResult {
|
|||||||
if !code.is_null() {
|
if !code.is_null() {
|
||||||
unsafe { code.write(exit_code as i32); }
|
unsafe { code.write(exit_code as i32); }
|
||||||
}
|
}
|
||||||
processor().manager().wait_done(thread::current().id(), pid);
|
processor().manager().remove(pid);
|
||||||
info!("wait: {} -> {}", thread::current().id(), pid);
|
info!("wait: {} -> {}", thread::current().id(), pid);
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
@ -253,8 +252,12 @@ fn sys_exit(exit_code: i32) -> SysResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sys_sleep(time: usize) -> SysResult {
|
fn sys_sleep(time: usize) -> SysResult {
|
||||||
use core::time::Duration;
|
if time >= 1 << 31 {
|
||||||
thread::sleep(Duration::from_millis(time as u64 * 10));
|
thread::park();
|
||||||
|
} else {
|
||||||
|
use core::time::Duration;
|
||||||
|
thread::sleep(Duration::from_millis(time as u64 * 10));
|
||||||
|
}
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user