diff --git a/src/libos/src/process/exit.rs b/src/libos/src/process/exit.rs index 5f275ae5..378e8811 100644 --- a/src/libos/src/process/exit.rs +++ b/src/libos/src/process/exit.rs @@ -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(¤t_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, diff --git a/src/libos/src/process/mod.rs b/src/libos/src/process/mod.rs index 5e7145d5..519286a7 100644 --- a/src/libos/src/process/mod.rs +++ b/src/libos/src/process/mod.rs @@ -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, diff --git a/src/libos/src/process/process.rs b/src/libos/src/process/process.rs index cf6840cc..38c2e166 100644 --- a/src/libos/src/process/process.rs +++ b/src/libos/src/process/process.rs @@ -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, diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index b4ad0e4e..a24309c4 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -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()); diff --git a/src/libos/src/process/thread.rs b/src/libos/src/process/thread.rs index 11e66625..e7dcdb2a 100644 --- a/src/libos/src/process/thread.rs +++ b/src/libos/src/process/thread.rs @@ -79,7 +79,7 @@ pub fn do_clone( let rlimits_ref = current.get_rlimits().clone(); let elf_path = ¤t.elf_path; let cwd = ¤t.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 {