continue refactoring process

master
WangRunji 6 years ago
parent d64681a26b
commit 98b3b12c96

@ -71,7 +71,7 @@ impl fmt::Debug for FileLike {
/// Pid type /// Pid type
/// For strong type separation /// For strong type separation
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pid(Option<usize>); pub struct Pid(Option<usize>);
impl Pid { impl Pid {
@ -79,10 +79,6 @@ impl Pid {
Pid(None) Pid(None)
} }
pub fn no_one() -> Self {
Pid(Some(0))
}
/// Return if it was uninitialized before this call /// Return if it was uninitialized before this call
/// When returning true, it usually means this is the first thread /// When returning true, it usually means this is the first thread
pub fn set_if_uninitialized(&mut self, tid: Tid) -> bool { pub fn set_if_uninitialized(&mut self, tid: Tid) -> bool {
@ -109,15 +105,21 @@ impl fmt::Display for Pid {
} }
pub struct Process { pub struct Process {
// resources
pub memory_set: MemorySet, pub memory_set: MemorySet,
pub files: BTreeMap<usize, FileLike>, pub files: BTreeMap<usize, FileLike>,
pub cwd: String, pub cwd: String,
futexes: BTreeMap<usize, Arc<Condvar>>,
// relationship
pub pid: Pid, // i.e. tgid, usually the tid of first thread pub pid: Pid, // i.e. tgid, usually the tid of first thread
pub ppid: Pid, // the pid of the parent process pub parent: Option<Arc<Mutex<Process>>>,
pub children: Vec<Weak<Mutex<Process>>>,
pub threads: Vec<Tid>, // threads in the same process pub threads: Vec<Tid>, // threads in the same process
pub exit_cond: Condvar, // notified when the whole process is going to terminate
pub exit_code: Option<usize>, // only available when last thread exits // for waiting child
futexes: BTreeMap<usize, Arc<Condvar>>, pub child_exit: Arc<Condvar>, // notified when the a child process is going to terminate
pub child_exit_code: BTreeMap<usize, usize>, // child process store its exit code here
} }
/// Records the mapping between pid and Process struct. /// Records the mapping between pid and Process struct.
@ -125,11 +127,6 @@ lazy_static! {
pub static ref PROCESSES: RwLock<BTreeMap<usize, Weak<Mutex<Process>>>> = RwLock::new(BTreeMap::new()); pub static ref PROCESSES: RwLock<BTreeMap<usize, Weak<Mutex<Process>>>> = RwLock::new(BTreeMap::new());
} }
/// Records the list of child processes
lazy_static! {
pub static ref CHILD_PROCESSES: RwLock<BTreeMap<usize, Vec<Arc<Mutex<Process>>>>> = RwLock::new(BTreeMap::new());
}
/// Let `rcore_thread` can switch between our `Thread` /// Let `rcore_thread` can switch between our `Thread`
impl rcore_thread::Context for Thread { impl rcore_thread::Context for Thread {
unsafe fn switch_to(&mut self, target: &mut rcore_thread::Context) { unsafe fn switch_to(&mut self, target: &mut rcore_thread::Context) {
@ -144,13 +141,9 @@ impl rcore_thread::Context for Thread {
if proc.pid.set_if_uninitialized(tid) { if proc.pid.set_if_uninitialized(tid) {
// first thread in the process // first thread in the process
// link to its ppid // link to its ppid
match CHILD_PROCESSES.write().entry(proc.ppid.get()) { if let Some(parent) = &proc.parent {
Entry::Vacant(entry) => { let mut parent = parent.lock();
entry.insert(vec![self.proc.clone()]); parent.children.push(Arc::downgrade(&self.proc));
}
Entry::Occupied(mut entry) => {
entry.get_mut().push(self.proc.clone());
}
} }
} }
// add it to threads // add it to threads
@ -161,6 +154,7 @@ impl rcore_thread::Context for Thread {
impl Thread { impl Thread {
/// Make a struct for the init thread /// Make a struct for the init thread
/// TODO: remove this, we only need `Context::null()`
pub unsafe fn new_init() -> Box<Thread> { pub unsafe fn new_init() -> Box<Thread> {
Box::new(Thread { Box::new(Thread {
context: Context::null(), context: Context::null(),
@ -172,10 +166,11 @@ impl Thread {
cwd: String::from("/"), cwd: String::from("/"),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid::uninitialized(), pid: Pid::uninitialized(),
ppid: Pid::no_one(), parent: None,
exit_cond: Condvar::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
exit_code: None child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new(),
})), })),
}) })
} }
@ -188,16 +183,18 @@ impl Thread {
context: unsafe { Context::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) }, context: unsafe { Context::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) },
kstack, kstack,
clear_child_tid: 0, clear_child_tid: 0,
// TODO: kernel thread should not have a process
proc: Arc::new(Mutex::new(Process { proc: Arc::new(Mutex::new(Process {
memory_set, memory_set,
files: BTreeMap::default(), files: BTreeMap::default(),
cwd: String::from("/"), cwd: String::from("/"),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid::uninitialized(), pid: Pid::uninitialized(),
ppid: Pid::no_one(), parent: None,
exit_cond: Condvar::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
exit_code: None child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new()
})), })),
}) })
} }
@ -286,10 +283,11 @@ impl Thread {
cwd: String::from("/"), cwd: String::from("/"),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid::uninitialized(), pid: Pid::uninitialized(),
ppid: Pid::no_one(), parent: None,
exit_cond: Condvar::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
exit_code: None child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new()
})), })),
}) })
} }
@ -300,7 +298,7 @@ impl Thread {
let memory_set = self.proc.lock().memory_set.clone(); let memory_set = self.proc.lock().memory_set.clone();
let files = self.proc.lock().files.clone(); let files = self.proc.lock().files.clone();
let cwd = self.proc.lock().cwd.clone(); let cwd = self.proc.lock().cwd.clone();
let ppid = self.proc.lock().pid.clone(); let parent = Some(self.proc.clone());
debug!("fork: finish clone MemorySet"); debug!("fork: finish clone MemorySet");
// MMU: copy data to the new space // MMU: copy data to the new space
@ -335,10 +333,11 @@ impl Thread {
cwd, cwd,
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid::uninitialized(), pid: Pid::uninitialized(),
ppid, parent,
exit_cond: Condvar::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
exit_code: None child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new()
})), })),
}) })
} }
@ -366,6 +365,13 @@ impl Process {
} }
self.futexes.get(&uaddr).unwrap().clone() self.futexes.get(&uaddr).unwrap().clone()
} }
pub fn report_exit_to_parent(&mut self, exit_code: usize) {
if let Some(parent) = &self.parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(self.pid.get(), exit_code);
parent.child_exit.notify_one();
}
}
} }

@ -1,7 +1,6 @@
//! Syscalls for process //! Syscalls for process
use super::*; use super::*;
use crate::process::{PROCESSES, CHILD_PROCESSES};
use crate::sync::Condvar; use crate::sync::Condvar;
/// Fork the current process. Return the child's PID. /// Fork the current process. Return the child's PID.
@ -40,11 +39,10 @@ pub fn sys_clone(flags: usize, newsp: usize, parent_tid: *mut u32, child_tid: *m
Ok(tid) Ok(tid)
} }
/// Wait the process exit. /// Wait for the process exit.
/// Return the PID. Store exit code to `code` if it's not null. /// Return the PID. Store exit code to `wstatus` if it's not null.
pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult { pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
info!("wait4: pid: {}, code: {:?}", pid, wstatus); info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let cur_pid = process().pid.get();
if !wstatus.is_null() { if !wstatus.is_null() {
process().memory_set.check_mut_ptr(wstatus)?; process().memory_set.check_mut_ptr(wstatus)?;
} }
@ -59,42 +57,37 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
_ => unimplemented!(), _ => unimplemented!(),
}; };
loop { loop {
use alloc::vec; let mut proc = process();
let all_child: Vec<_> = CHILD_PROCESSES.read().get(&cur_pid).unwrap().clone(); // check child_exit_code
let wait_procs = match target { let find = match target {
WaitFor::AnyChild => all_child, WaitFor::AnyChild => proc.child_exit_code
WaitFor::Pid(pid) => { .iter().next().map(|(&pid, &code)| (pid, code)),
// check if pid is a child WaitFor::Pid(pid) => proc.child_exit_code
if let Some(proc) = all_child.iter().find(|p| p.lock().pid.get() == pid) { .get(&pid).map(|&code| (pid, code)),
vec![proc.clone()]
} else {
vec![]
}
}
}; };
if wait_procs.is_empty() { // if found, return
return Err(SysError::ECHILD); if let Some((pid, exit_code)) = find {
} proc.child_exit_code.remove(&pid);
if !wstatus.is_null() {
for proc_lock in wait_procs.iter() { unsafe { wstatus.write(exit_code as i32); }
let proc = proc_lock.lock();
if let Some(exit_code) = proc.exit_code {
// recycle process
let pid = proc.pid.get();
drop(proc);
let mut child_processes = CHILD_PROCESSES.write();
child_processes.get_mut(&cur_pid).unwrap().retain(|p| p.lock().pid.get() != pid);
child_processes.remove(&pid);
return Ok(pid);
} }
return Ok(pid);
} }
info!("wait: {} -> {:?}, sleep", thread::current().id(), target); // if not, check pid
let children: Vec<_> = proc.children.iter()
for proc in wait_procs.iter() { .filter_map(|weak| weak.upgrade())
proc.lock().exit_cond.add_to_wait_queue(); .collect();
let invalid = match target {
WaitFor::AnyChild => children.len() == 0,
WaitFor::Pid(pid) => children.iter().find(|p| p.lock().pid.get() == pid).is_none(),
};
if invalid {
return Err(SysError::ECHILD);
} }
thread::park(); info!("wait: thread {} -> {:?}, sleep", thread::current().id(), target);
let condvar = proc.child_exit.clone();
drop(proc); // must release lock of current process
condvar._wait();
} }
} }
@ -177,7 +170,7 @@ pub fn sys_gettid() -> SysResult {
/// Get the parent process id /// Get the parent process id
pub fn sys_getppid() -> SysResult { pub fn sys_getppid() -> SysResult {
Ok(process().ppid.get()) Ok(process().parent.as_ref().unwrap().lock().pid.get())
} }
/// Exit the current thread /// Exit the current thread
@ -188,8 +181,7 @@ pub fn sys_exit(exit_code: usize) -> ! {
proc.threads.retain(|&id| id != tid); proc.threads.retain(|&id| id != tid);
if proc.threads.len() == 0 { if proc.threads.len() == 0 {
// last thread // last thread
proc.exit_code = Some(exit_code); proc.report_exit_to_parent(exit_code);
proc.exit_cond.notify_all();
} }
drop(proc); drop(proc);
@ -209,7 +201,7 @@ pub fn sys_exit(exit_code: usize) -> ! {
unreachable!(); unreachable!();
} }
/// Exit the current thread group (i.e. progress) /// Exit the current thread group (i.e. process)
pub fn sys_exit_group(exit_code: usize) -> ! { pub fn sys_exit_group(exit_code: usize) -> ! {
let mut proc = process(); let mut proc = process();
info!("exit_group: {}, code: {}", proc.pid, exit_code); info!("exit_group: {}, code: {}", proc.pid, exit_code);
@ -218,8 +210,7 @@ pub fn sys_exit_group(exit_code: usize) -> ! {
for tid in proc.threads.iter() { for tid in proc.threads.iter() {
processor().manager().exit(*tid, exit_code); processor().manager().exit(*tid, exit_code);
} }
proc.exit_code = Some(exit_code); proc.report_exit_to_parent(exit_code);
proc.exit_cond.notify_all();
drop(proc); drop(proc);
processor().yield_now(); processor().yield_now();

Loading…
Cancel
Save