Correct init process, allow waiting on any children, reap zombies in init
This commit is contained in:
		
							parent
							
								
									ff227737bf
								
							
						
					
					
						commit
						25743a89a2
					
				
					 4 changed files with 122 additions and 46 deletions
				
			
		| 
						 | 
				
			
			@ -691,13 +691,14 @@ pub fn exit(status: usize) -> ! {
 | 
			
		|||
        };
 | 
			
		||||
 | 
			
		||||
        let mut close_files = Vec::new();
 | 
			
		||||
        {
 | 
			
		||||
        let (pid, ppid) = {
 | 
			
		||||
            let mut context = context_lock.write();
 | 
			
		||||
            if Arc::strong_count(&context.files) == 1 {
 | 
			
		||||
                mem::swap(context.files.lock().deref_mut(), &mut close_files);
 | 
			
		||||
            }
 | 
			
		||||
            context.files = Arc::new(Mutex::new(Vec::new()));
 | 
			
		||||
        }
 | 
			
		||||
            (context.id, context.ppid)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /// Files must be closed while context is valid so that messages can be passed
 | 
			
		||||
        for (fd, file_option) in close_files.drain(..).enumerate() {
 | 
			
		||||
| 
						 | 
				
			
			@ -716,7 +717,19 @@ pub fn exit(status: usize) -> ! {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let (vfork, ppid) = {
 | 
			
		||||
        /// Transfer child processes to parent
 | 
			
		||||
        {
 | 
			
		||||
            let contexts = context::contexts();
 | 
			
		||||
            for (_id, context_lock) in contexts.iter() {
 | 
			
		||||
                let mut context = context_lock.write();
 | 
			
		||||
                if context.ppid == pid {
 | 
			
		||||
                    context.ppid = ppid;
 | 
			
		||||
                    context.vfork = false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let (vfork, children) = {
 | 
			
		||||
            let mut context = context_lock.write();
 | 
			
		||||
 | 
			
		||||
            context.image.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -730,18 +743,28 @@ pub fn exit(status: usize) -> ! {
 | 
			
		|||
 | 
			
		||||
            context.status = context::Status::Exited(status);
 | 
			
		||||
 | 
			
		||||
            context.waitpid.notify();
 | 
			
		||||
            let children = context.waitpid.receive_all();
 | 
			
		||||
 | 
			
		||||
            (vfork, context.ppid)
 | 
			
		||||
            (vfork, children)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if vfork {
 | 
			
		||||
        {
 | 
			
		||||
            let contexts = context::contexts();
 | 
			
		||||
            if let Some(parent_lock) = contexts.get(ppid) {
 | 
			
		||||
                let mut parent = parent_lock.write();
 | 
			
		||||
                if ! parent.unblock() {
 | 
			
		||||
                    println!("{} not blocked for exit vfork unblock", ppid);
 | 
			
		||||
                let waitpid = {
 | 
			
		||||
                    let mut parent = parent_lock.write();
 | 
			
		||||
                    if vfork {
 | 
			
		||||
                        if ! parent.unblock() {
 | 
			
		||||
                            println!("{} not blocked for exit vfork unblock", ppid);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    parent.waitpid.clone()
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                for (c_pid, c_status) in children {
 | 
			
		||||
                    waitpid.send(c_pid, c_status);
 | 
			
		||||
                }
 | 
			
		||||
                waitpid.send(pid, status);
 | 
			
		||||
            } else {
 | 
			
		||||
                println!("{} not found for exit vfork unblock", ppid);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -977,45 +1000,64 @@ pub fn virttophys(virtual_address: usize) -> Result<usize> {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
 | 
			
		||||
    loop {
 | 
			
		||||
        let mut exited = false;
 | 
			
		||||
        let mut running;
 | 
			
		||||
        let waitpid;
 | 
			
		||||
fn reap(pid: usize) -> Result<usize> {
 | 
			
		||||
    // Spin until not running
 | 
			
		||||
    let mut running = false;
 | 
			
		||||
    while running {
 | 
			
		||||
        {
 | 
			
		||||
            let contexts = context::contexts();
 | 
			
		||||
            let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?;
 | 
			
		||||
            let context = context_lock.read();
 | 
			
		||||
            if let context::Status::Exited(status) = context.status {
 | 
			
		||||
                if status_ptr != 0 {
 | 
			
		||||
                    let status_slice = validate_slice_mut(status_ptr as *mut usize, 1)?;
 | 
			
		||||
                    status_slice[0] = status;
 | 
			
		||||
                }
 | 
			
		||||
                exited = true;
 | 
			
		||||
            }
 | 
			
		||||
            running = context.running;
 | 
			
		||||
            waitpid = context.waitpid.clone();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if exited {
 | 
			
		||||
            // Spin until not running
 | 
			
		||||
            while running {
 | 
			
		||||
                {
 | 
			
		||||
                    let contexts = context::contexts();
 | 
			
		||||
                    let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?;
 | 
			
		||||
                    let context = context_lock.read();
 | 
			
		||||
                    running = context.running;
 | 
			
		||||
                }
 | 
			
		||||
        arch::interrupt::pause();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
                arch::interrupt::pause();
 | 
			
		||||
    let mut contexts = context::contexts_mut();
 | 
			
		||||
    contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
 | 
			
		||||
    let waitpid = {
 | 
			
		||||
        let contexts = context::contexts();
 | 
			
		||||
        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
 | 
			
		||||
        let context = context_lock.read();
 | 
			
		||||
        context.waitpid.clone()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let mut tmp = [0];
 | 
			
		||||
    let status_slice = if status_ptr != 0 {
 | 
			
		||||
        validate_slice_mut(status_ptr as *mut usize, 1)?
 | 
			
		||||
    } else {
 | 
			
		||||
        &mut tmp
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if pid == 0 {
 | 
			
		||||
        if flags & WNOHANG == WNOHANG {
 | 
			
		||||
            if let Some((w_pid, status)) = waitpid.receive_any_nonblock() {
 | 
			
		||||
                status_slice[0] = status;
 | 
			
		||||
                reap(w_pid)
 | 
			
		||||
            } else {
 | 
			
		||||
                Ok(0)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let mut contexts = context::contexts_mut();
 | 
			
		||||
            return contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid));
 | 
			
		||||
        } else if flags & WNOHANG == WNOHANG {
 | 
			
		||||
            return Ok(0);
 | 
			
		||||
        } else {
 | 
			
		||||
            waitpid.wait();
 | 
			
		||||
            let (w_pid, status) = waitpid.receive_any();
 | 
			
		||||
            status_slice[0] = status;
 | 
			
		||||
            reap(w_pid)
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if flags & WNOHANG == WNOHANG {
 | 
			
		||||
            if let Some(status) = waitpid.receive_nonblock(&pid) {
 | 
			
		||||
                status_slice[0] = status;
 | 
			
		||||
                reap(pid)
 | 
			
		||||
            } else {
 | 
			
		||||
                Ok(0)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            let status = waitpid.receive(&pid);
 | 
			
		||||
            status_slice[0] = status;
 | 
			
		||||
            reap(pid)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue