fix Process dropping by making `proc.parent` a weak reference

master
WangRunji 6 years ago
parent 9df9d01e68
commit ba8d08d733

@ -22,6 +22,7 @@ use crate::sync::{Condvar, SpinNoIrqLock as Mutex};
use super::abi::{self, ProcInitInfo}; use super::abi::{self, ProcInitInfo};
use core::mem::uninitialized; use core::mem::uninitialized;
use rcore_fs::vfs::INode; use rcore_fs::vfs::INode;
use crate::processor;
pub struct Thread { pub struct Thread {
context: Context, context: Context,
@ -66,7 +67,7 @@ pub struct Process {
// relationship // 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 parent: Option<Arc<Mutex<Process>>>, pub parent: Weak<Mutex<Process>>,
pub children: Vec<Weak<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
@ -125,7 +126,7 @@ impl Thread {
exec_path: String::new(), exec_path: String::new(),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid(0), pid: Pid(0),
parent: None, parent: Weak::new(),
children: Vec::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
child_exit: Arc::new(Condvar::new()), child_exit: Arc::new(Condvar::new()),
@ -303,7 +304,7 @@ impl Thread {
exec_path: String::from(exec_path), exec_path: String::from(exec_path),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid(0), pid: Pid(0),
parent: None, parent: Weak::new(),
children: Vec::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
child_exit: Arc::new(Condvar::new()), child_exit: Arc::new(Condvar::new()),
@ -329,7 +330,7 @@ impl Thread {
exec_path: proc.exec_path.clone(), exec_path: proc.exec_path.clone(),
futexes: BTreeMap::default(), futexes: BTreeMap::default(),
pid: Pid(0), pid: Pid(0),
parent: Some(self.proc.clone()), parent: Arc::downgrade(&self.proc),
children: Vec::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
child_exit: Arc::new(Condvar::new()), child_exit: Arc::new(Condvar::new()),
@ -403,6 +404,20 @@ impl Process {
} }
self.futexes.get(&uaddr).unwrap().clone() self.futexes.get(&uaddr).unwrap().clone()
} }
/// Exit the process.
/// Kill all threads and notify parent with the exit code.
pub fn exit(&mut self, exit_code: usize) {
// quit all threads
for tid in self.threads.iter() {
processor().manager().exit(*tid, 1);
}
// notify parent and fill exit code
if let Some(parent) = self.parent.upgrade() {
let mut parent = parent.lock();
parent.child_exit_code.insert(self.pid.get(), exit_code);
parent.child_exit.notify_one();
}
}
} }
trait ToMemoryAttr { trait ToMemoryAttr {

@ -524,7 +524,7 @@ impl Syscall<'_> {
arg3: usize, arg3: usize,
) -> SysResult { ) -> SysResult {
info!( info!(
"ioctl: fd: {}, request: {:x}, args: {} {} {}", "ioctl: fd: {}, request: {:#x}, args: {:#x} {:#x} {:#x}",
fd, request, arg1, arg2, arg3 fd, request, arg1, arg2, arg3
); );
let mut proc = self.process(); let mut proc = self.process();

@ -54,7 +54,6 @@ impl Syscall<'_> {
let new_thread = self let new_thread = self
.thread .thread
.clone(self.tf, newsp, newtls, child_tid as usize); .clone(self.tf, newsp, newtls, child_tid as usize);
// FIXME: parent pid
let tid = processor().manager().add(new_thread); let tid = processor().manager().add(new_thread);
processor().manager().detach(tid); processor().manager().detach(tid);
info!("clone: {} -> {}", thread::current().id(), tid); info!("clone: {} -> {}", thread::current().id(), tid);
@ -66,7 +65,7 @@ impl Syscall<'_> {
/// Wait for the process exit. /// Wait for the process exit.
/// Return the PID. Store exit code to `wstatus` if it's not null. /// Return the PID. Store exit code to `wstatus` if it's not null.
pub fn sys_wait4(&mut self, pid: isize, wstatus: *mut i32) -> SysResult { pub fn sys_wait4(&mut self, pid: isize, wstatus: *mut i32) -> SysResult {
//info!("wait4: pid: {}, code: {:?}", pid, wstatus); info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let wstatus = if !wstatus.is_null() { let wstatus = if !wstatus.is_null() {
Some(unsafe { self.vm().check_write_ptr(wstatus)? }) Some(unsafe { self.vm().check_write_ptr(wstatus)? })
} else { } else {
@ -75,10 +74,12 @@ impl Syscall<'_> {
#[derive(Debug)] #[derive(Debug)]
enum WaitFor { enum WaitFor {
AnyChild, AnyChild,
AnyChildInGroup,
Pid(usize), Pid(usize),
} }
let target = match pid { let target = match pid {
-1 | 0 => WaitFor::AnyChild, -1 => WaitFor::AnyChild,
0 => WaitFor::AnyChildInGroup,
p if p > 0 => WaitFor::Pid(p as usize), p if p > 0 => WaitFor::Pid(p as usize),
_ => unimplemented!(), _ => unimplemented!(),
}; };
@ -86,7 +87,7 @@ impl Syscall<'_> {
let mut proc = self.process(); let mut proc = self.process();
// check child_exit_code // check child_exit_code
let find = match target { let find = match target {
WaitFor::AnyChild => proc WaitFor::AnyChild | WaitFor::AnyChildInGroup => proc
.child_exit_code .child_exit_code
.iter() .iter()
.next() .next()
@ -102,17 +103,19 @@ impl Syscall<'_> {
return Ok(pid); return Ok(pid);
} }
// if not, check pid // if not, check pid
let children: Vec<_> = proc let invalid = {
.children let children: Vec<_> = proc
.iter() .children
.filter_map(|weak| weak.upgrade())
.collect();
let invalid = match target {
WaitFor::AnyChild => children.len() == 0,
WaitFor::Pid(pid) => children
.iter() .iter()
.find(|p| p.lock().pid.get() == pid) .filter_map(|weak| weak.upgrade())
.is_none(), .collect();
match target {
WaitFor::AnyChild | WaitFor::AnyChildInGroup => children.len() == 0,
WaitFor::Pid(pid) => children
.iter()
.find(|p| p.lock().pid.get() == pid)
.is_none(),
}
}; };
if invalid { if invalid {
return Err(SysError::ECHILD); return Err(SysError::ECHILD);
@ -204,7 +207,7 @@ impl Syscall<'_> {
/// Kill the process /// Kill the process
pub fn sys_kill(&mut self, pid: usize, sig: usize) -> SysResult { pub fn sys_kill(&mut self, pid: usize, sig: usize) -> SysResult {
info!( info!(
"kill: {} killed: {} with sig {}", "kill: thread {} kill process {} with signal {}",
thread::current().id(), thread::current().id(),
pid, pid,
sig sig
@ -215,21 +218,8 @@ impl Syscall<'_> {
self.sys_exit_group(sig); self.sys_exit_group(sig);
} else { } else {
if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) { if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) {
let proc = proc_arc.lock(); let mut proc = proc_arc.lock();
// quit all threads proc.exit(sig);
for tid in proc.threads.iter() {
processor().manager().exit(*tid, sig);
}
// notify parent and fill exit code
// avoid deadlock
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, sig);
parent.child_exit.notify_one();
}
Ok(0) Ok(0)
} else { } else {
Err(SysError::EINVAL) Err(SysError::EINVAL)
@ -252,7 +242,7 @@ impl Syscall<'_> {
/// Get the parent process id /// Get the parent process id
pub fn sys_getppid(&mut self) -> SysResult { pub fn sys_getppid(&mut self) -> SysResult {
if let Some(parent) = self.process().parent.as_ref() { if let Some(parent) = self.process().parent.upgrade() {
Ok(parent.lock().pid.get()) Ok(parent.lock().pid.get())
} else { } else {
Ok(0) Ok(0)
@ -266,26 +256,15 @@ impl Syscall<'_> {
let mut proc = self.process(); let mut proc = self.process();
proc.threads.retain(|&id| id != tid); proc.threads.retain(|&id| id != tid);
// for last thread, // for last thread, exit the process
// notify parent and fill exit code if proc.threads.len() == 0 {
// avoid deadlock proc.exit(exit_code);
let exit = proc.threads.len() == 0;
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if exit {
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, exit_code);
parent.child_exit.notify_one();
}
} }
// perform futex wake 1 // perform futex wake 1
// ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html // ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html
// FIXME: do it in all possible ways a thread can exit // FIXME: do it in all possible ways a thread can exit
// it has memory access so we can't move it to Thread::drop? // it has memory access so we can't move it to Thread::drop?
let mut proc = self.process();
let clear_child_tid = self.thread.clear_child_tid as *mut u32; let clear_child_tid = self.thread.clear_child_tid as *mut u32;
if !clear_child_tid.is_null() { if !clear_child_tid.is_null() {
info!("exit: futex {:#?} wake 1", clear_child_tid); info!("exit: futex {:#?} wake 1", clear_child_tid);
@ -304,24 +283,10 @@ impl Syscall<'_> {
/// Exit the current thread group (i.e. process) /// Exit the current thread group (i.e. process)
pub fn sys_exit_group(&mut self, exit_code: usize) -> ! { pub fn sys_exit_group(&mut self, exit_code: usize) -> ! {
let proc = self.process(); let mut proc = self.process();
info!("exit_group: {}, code: {}", proc.pid, exit_code); info!("exit_group: {}, code: {}", proc.pid, exit_code);
// quit all threads proc.exit(exit_code);
for tid in proc.threads.iter() {
processor().manager().exit(*tid, exit_code);
}
// notify parent and fill exit code
// avoid deadlock
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, exit_code);
parent.child_exit.notify_one();
}
processor().yield_now(); processor().yield_now();
unreachable!(); unreachable!();

Loading…
Cancel
Save