From a168c989cf5042565a1273ce6d8da36ea1881e2f Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Fri, 3 Nov 2023 20:36:10 -0600 Subject: [PATCH] exit --- kernel/proc.c | 42 +------------- kernel/rustkernel/src/proc/process.rs | 80 +++++++++++++++++++++++---- kernel/rustkernel/src/syscall.rs | 6 +- kernel/rustkernel/src/trap.rs | 4 +- 4 files changed, 75 insertions(+), 57 deletions(-) diff --git a/kernel/proc.c b/kernel/proc.c index 0809d0c..44f47f0 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -112,47 +112,7 @@ void reparent(struct proc *p); // Exit the current process. Does not return. // An exited process remains in the zombie state // until its parent calls wait(). -void -exit(int status) -{ - struct proc *p = myproc(); - - if(p == initproc) - panic("init exiting"); - - // Close all open files. - for(int fd = 0; fd < NOFILE; fd++){ - if(p->ofile[fd]){ - struct file *f = p->ofile[fd]; - fileclose(f); - p->ofile[fd] = 0; - } - } - - begin_op(); - iput(p->cwd); - end_op(); - p->cwd = 0; - - acquire(&wait_lock); - - // Give any children to init. - reparent(p); - - // Parent might be sleeping in wait(). - wakeup(p->parent); - - acquire(&p->lock); - - p->xstate = status; - p->state = ZOMBIE; - - release(&wait_lock); - - // Jump into the scheduler, never to return. - sched(); - panic("zombie exit"); -} +void exit(int status); // Wait for a child process to exit and return its pid. // Return -1 if this process has no children. diff --git a/kernel/rustkernel/src/proc/process.rs b/kernel/rustkernel/src/proc/process.rs index d5633f9..58c3bd1 100644 --- a/kernel/rustkernel/src/proc/process.rs +++ b/kernel/rustkernel/src/proc/process.rs @@ -1,9 +1,14 @@ #![allow(clippy::comparison_chain)] -use super::{context::Context, cpu::Cpu, scheduler::wakeup, trapframe::Trapframe}; +use super::{context::Context, cpu::Cpu, scheduler::{wakeup, sched}, trapframe::Trapframe}; use crate::{ arch::riscv::{Pagetable, PTE_W, PTE_R, PTE_X, PGSIZE, memlayout::{TRAMPOLINE, TRAPFRAME}}, - fs::{file::{File, Inode, filedup}, idup}, + fs::{ + file::{File, Inode, filedup, fileclose}, + idup, + iput, + log::LogOperation, + }, mem::{ kalloc::{kfree, kalloc}, memset, @@ -11,6 +16,7 @@ use crate::{ }, sync::spinlock::Spinlock, string::safestrcpy, + println, }; use core::{ ffi::{c_char, c_void}, @@ -35,7 +41,7 @@ extern "C" { pub fn userinit(); pub fn forkret(); // pub fn fork() -> i32; - pub fn exit(status: i32) -> !; + // pub fn exit(status: i32) -> !; pub fn wait(addr: u64) -> i32; pub fn procdump(); pub fn proc_mapstacks(kpgtbl: Pagetable); @@ -299,6 +305,60 @@ impl Process { Ok(pid) } + /// Pass p's abandoned children to init. + /// Caller must hold wait_lock. + pub unsafe fn reparent(&self) { + for p in proc.iter_mut() { + if p.parent == addr_of!(*self).cast_mut() { + p.parent = initproc; + wakeup(initproc.cast()); + } + } + } + + /// Exit the current process. Does not return. + /// An exited process remains in the zombie state + /// until its parent calls wait(). + pub unsafe fn exit(&mut self, status: i32) -> ! { + if addr_of_mut!(*self) == initproc { + panic!("init exiting"); + } + + // Close all open files. + for file in self.ofile.iter_mut() { + if !file.is_null() { + fileclose(*file); + *file = null_mut(); + } + } + + { + let _operation = LogOperation::new(); + iput(self.cwd); + } + self.cwd = null_mut(); + + { + let _guard = wait_lock.lock(); + + // Give any children to init. + self.reparent(); + + // Parent might be sleeping in wait(). + wakeup(self.parent.cast()); + + self.lock.lock_unguarded(); + self.xstate = status; + self.state = ProcessState::Zombie; + } + + // Jump into the scheduler, never to return. + sched(); + loop { + unreachable!(); + } + } + /// Kill the process with the given pid. /// Returns true if the process was killed. /// The victim won't exit until it tries to return @@ -376,16 +436,14 @@ pub unsafe extern "C" fn proc_freepagetable(pagetable: Pagetable, size: u64) { Process::free_pagetable(pagetable, size as usize) } -/// Pass p's abandoned children to init. -/// Caller must hold wait_lock. #[no_mangle] pub unsafe extern "C" fn reparent(p: *mut Process) { - for pp in proc.iter_mut().map(|p: &mut Process| addr_of_mut!(*p)) { - if (*pp).parent == p { - (*pp).parent = initproc; - wakeup(initproc.cast()); - } - } + (*p).reparent() +} + +#[no_mangle] +pub unsafe extern "C" fn exit(status: i32) -> ! { + Process::current().unwrap().exit(status) } /// Kill the process with the given pid. diff --git a/kernel/rustkernel/src/syscall.rs b/kernel/rustkernel/src/syscall.rs index beecd6f..22f3e36 100644 --- a/kernel/rustkernel/src/syscall.rs +++ b/kernel/rustkernel/src/syscall.rs @@ -59,9 +59,9 @@ impl Syscall { match self { Syscall::Fork => Process::fork().unwrap_or(-1) as i64 as u64, Syscall::Exit => { - let mut n = 0i32; - argint(0, addr_of_mut!(n)); - process::exit(n) + let mut status = 0i32; + argint(0, addr_of_mut!(status)); + Process::current().unwrap().exit(status) } Syscall::Wait => { let mut p = 0u64; diff --git a/kernel/rustkernel/src/trap.rs b/kernel/rustkernel/src/trap.rs index 8e733f9..6c64e11 100644 --- a/kernel/rustkernel/src/trap.rs +++ b/kernel/rustkernel/src/trap.rs @@ -232,7 +232,7 @@ pub unsafe extern "C" fn usertrap() { // System call if proc.is_killed() { - exit(-1); + proc.exit(-1); } // sepc points to the ecall instruction, but @@ -259,7 +259,7 @@ pub unsafe extern "C" fn usertrap() { } if proc.is_killed() { - exit(-1); + proc.exit(-1); } // Give up the CPU if this is a timer interrupt.