Fix thread exiting but not being freed

This commit is contained in:
Tate, Hongliang Tian 2020-03-31 14:47:31 +00:00
parent 23329efe14
commit a7400ca6dc
5 changed files with 46 additions and 23 deletions

@ -15,6 +15,7 @@ unsafe impl Send for ChildProcessFilter {}
pub fn do_exit(exit_status: i32) {
let current_ref = get_current();
let mut current = current_ref.lock().unwrap();
let parent_ref = current.get_parent().clone();
// Update current
current.exit_status = exit_status;
current.status = Status::ZOMBIE;
@ -34,8 +35,15 @@ pub fn do_exit(exit_status: i32) {
futex_wake(ctid as *const i32, 1);
}
// If the process is detached, no need to notify the parent
if current.is_detached {
let current_tid = current.get_tid();
drop(current);
remove_zombie_child(&parent_ref, current_tid);
return;
}
// Notify the parent process if necessary
let parent_ref = current.get_parent().clone();
let (mut parent, current) = {
// Always lock parent before its child
drop(current);
@ -103,34 +111,44 @@ pub fn do_wait4(child_filter: &ChildProcessFilter, exit_status: &mut i32) -> Res
waiter
};
// Wait until a child has interesting events
let child_pid = waiter.sleep_until_woken_with_result();
let mut current = current_ref.lock().unwrap();
let child_i = {
let mut child_i_opt = None;
for (child_i, child_ref) in current.get_children_iter().enumerate() {
let child = child_ref.lock().unwrap();
if child.get_pid() != child_pid {
continue;
}
// Remove the child from the parent
*exit_status = remove_zombie_child(&current_ref, child_pid);
if child.get_status() != Status::ZOMBIE {
panic!("THIS SHOULD NEVER HAPPEN!");
}
child_i_opt = Some(child_i);
*exit_status = child.get_exit_status();
}
child_i_opt.unwrap()
};
current.children.swap_remove(child_i);
let mut current = current_ref.lock().unwrap();
current.waiting_children = None;
// Release the last reference to the child process
process_table::remove(child_pid);
Ok(child_pid)
}
fn remove_zombie_child(parent_ref: &ProcessRef, child_tid: pid_t) -> i32 {
// Find the zombie child process
let mut parent = parent_ref.lock().unwrap();
let (child_i, child_ref) = parent
.get_children_iter()
.enumerate()
.find(|(child_i, child_ref)| {
let child = child_ref.lock().unwrap();
if child.get_tid() != child_tid {
return false;
}
assert!(child.get_status() == Status::ZOMBIE);
true
})
.expect("cannot find the zombie child");
// Remove the zombie child from parent
parent.children.swap_remove(child_i);
// Remove the zombie child from process table
process_table::remove(child_tid);
// Return the exit status
let child = child_ref.lock().unwrap();
child.get_exit_status()
}
fn lock_two_in_order<'a>(
first_ref: &'a ProcessRef,
second_ref: &'a ProcessRef,

@ -23,6 +23,7 @@ pub struct Process {
tgid: pid_t,
host_tid: pid_t,
exit_status: i32,
is_detached: bool,
// TODO: move cwd, root_inode into a FileSystem structure
// TODO: should cwd be a String or INode?
cwd: String,

@ -14,6 +14,7 @@ lazy_static! {
tgid: 0,
host_tid: 0,
exit_status: 0,
is_detached: false,
cwd: "/".to_owned(),
elf_path: "/".to_owned(),
clear_child_tid: None,
@ -28,6 +29,7 @@ lazy_static! {
}
impl Process {
// TODO: this constructor has become complicated enough to justify using builders
pub fn new(
cwd: &str,
elf_path: &str,
@ -35,6 +37,7 @@ impl Process {
vm_ref: ProcessVMRef,
file_table_ref: FileTableRef,
rlimits_ref: ResourceLimitsRef,
is_detached: bool,
) -> Result<(pid_t, ProcessRef)> {
let new_pid = process_table::alloc_pid();
let new_process_ref = Arc::new(SgxMutex::new(Process {
@ -48,6 +51,7 @@ impl Process {
elf_path: elf_path.to_owned(),
clear_child_tid: None,
exit_status: 0,
is_detached: is_detached,
parent: None,
children: Vec::new(),
waiting_children: None,

@ -111,7 +111,7 @@ fn new_process(
Arc::new(SgxMutex::new(files))
};
let rlimits_ref = Default::default();
Process::new(&cwd, elf_path, task, vm_ref, files_ref, rlimits_ref)?
Process::new(&cwd, elf_path, task, vm_ref, files_ref, rlimits_ref, false)?
};
parent_adopts_new_child(&parent_ref, &new_process_ref);
process_table::put(new_pid, new_process_ref.clone());

@ -79,7 +79,7 @@ pub fn do_clone(
let rlimits_ref = current.get_rlimits().clone();
let elf_path = &current.elf_path;
let cwd = &current.cwd;
Process::new(cwd, elf_path, task, vm_ref, files_ref, rlimits_ref)?
Process::new(cwd, elf_path, task, vm_ref, files_ref, rlimits_ref, true)?
};
if let Some(ctid) = ctid {