continue refactoring process

master
WangRunji 6 years ago
parent d64681a26b
commit 98b3b12c96

@ -71,7 +71,7 @@ impl fmt::Debug for FileLike {
/// Pid type
/// For strong type separation
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pid(Option<usize>);
impl Pid {
@ -79,10 +79,6 @@ impl Pid {
Pid(None)
}
pub fn no_one() -> Self {
Pid(Some(0))
}
/// Return if it was uninitialized before this call
/// When returning true, it usually means this is the first thread
pub fn set_if_uninitialized(&mut self, tid: Tid) -> bool {
@ -109,15 +105,21 @@ impl fmt::Display for Pid {
}
pub struct Process {
// resources
pub memory_set: MemorySet,
pub files: BTreeMap<usize, FileLike>,
pub cwd: String,
futexes: BTreeMap<usize, Arc<Condvar>>,
// relationship
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 exit_cond: Condvar, // notified when the whole process is going to terminate
pub exit_code: Option<usize>, // only available when last thread exits
futexes: BTreeMap<usize, Arc<Condvar>>,
// for waiting child
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.
@ -125,11 +127,6 @@ lazy_static! {
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`
impl rcore_thread::Context for Thread {
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) {
// first thread in the process
// link to its ppid
match CHILD_PROCESSES.write().entry(proc.ppid.get()) {
Entry::Vacant(entry) => {
entry.insert(vec![self.proc.clone()]);
}
Entry::Occupied(mut entry) => {
entry.get_mut().push(self.proc.clone());
}
if let Some(parent) = &proc.parent {
let mut parent = parent.lock();
parent.children.push(Arc::downgrade(&self.proc));
}
}
// add it to threads
@ -161,6 +154,7 @@ impl rcore_thread::Context for Thread {
impl Thread {
/// Make a struct for the init thread
/// TODO: remove this, we only need `Context::null()`
pub unsafe fn new_init() -> Box<Thread> {
Box::new(Thread {
context: Context::null(),
@ -172,10 +166,11 @@ impl Thread {
cwd: String::from("/"),
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid: Pid::no_one(),
exit_cond: Condvar::new(),
parent: None,
children: 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()) },
kstack,
clear_child_tid: 0,
// TODO: kernel thread should not have a process
proc: Arc::new(Mutex::new(Process {
memory_set,
files: BTreeMap::default(),
cwd: String::from("/"),
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid: Pid::no_one(),
exit_cond: Condvar::new(),
parent: None,
children: 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("/"),
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid: Pid::no_one(),
exit_cond: Condvar::new(),
parent: None,
children: 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 files = self.proc.lock().files.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");
// MMU: copy data to the new space
@ -335,10 +333,11 @@ impl Thread {
cwd,
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
ppid,
exit_cond: Condvar::new(),
parent,
children: 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()
}
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
use super::*;
use crate::process::{PROCESSES, CHILD_PROCESSES};
use crate::sync::Condvar;
/// 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)
}
/// Wait the process exit.
/// Return the PID. Store exit code to `code` if it's not null.
/// Wait for the process exit.
/// Return the PID. Store exit code to `wstatus` if it's not null.
pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let cur_pid = process().pid.get();
if !wstatus.is_null() {
process().memory_set.check_mut_ptr(wstatus)?;
}
@ -59,42 +57,37 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
_ => unimplemented!(),
};
loop {
use alloc::vec;
let all_child: Vec<_> = CHILD_PROCESSES.read().get(&cur_pid).unwrap().clone();
let wait_procs = match target {
WaitFor::AnyChild => all_child,
WaitFor::Pid(pid) => {
// check if pid is a child
if let Some(proc) = all_child.iter().find(|p| p.lock().pid.get() == pid) {
vec![proc.clone()]
} else {
vec![]
}
}
let mut proc = process();
// check child_exit_code
let find = match target {
WaitFor::AnyChild => proc.child_exit_code
.iter().next().map(|(&pid, &code)| (pid, code)),
WaitFor::Pid(pid) => proc.child_exit_code
.get(&pid).map(|&code| (pid, code)),
};
if wait_procs.is_empty() {
return Err(SysError::ECHILD);
}
for proc_lock in wait_procs.iter() {
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);
// if found, return
if let Some((pid, exit_code)) = find {
proc.child_exit_code.remove(&pid);
if !wstatus.is_null() {
unsafe { wstatus.write(exit_code as i32); }
}
return Ok(pid);
}
info!("wait: {} -> {:?}, sleep", thread::current().id(), target);
for proc in wait_procs.iter() {
proc.lock().exit_cond.add_to_wait_queue();
// if not, check pid
let children: Vec<_> = proc.children.iter()
.filter_map(|weak| weak.upgrade())
.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
pub fn sys_getppid() -> SysResult {
Ok(process().ppid.get())
Ok(process().parent.as_ref().unwrap().lock().pid.get())
}
/// Exit the current thread
@ -188,8 +181,7 @@ pub fn sys_exit(exit_code: usize) -> ! {
proc.threads.retain(|&id| id != tid);
if proc.threads.len() == 0 {
// last thread
proc.exit_code = Some(exit_code);
proc.exit_cond.notify_all();
proc.report_exit_to_parent(exit_code);
}
drop(proc);
@ -209,7 +201,7 @@ pub fn sys_exit(exit_code: usize) -> ! {
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) -> ! {
let mut proc = process();
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() {
processor().manager().exit(*tid, exit_code);
}
proc.exit_code = Some(exit_code);
proc.exit_cond.notify_all();
proc.report_exit_to_parent(exit_code);
drop(proc);
processor().yield_now();

Loading…
Cancel
Save