diff options
Diffstat (limited to 'sys/kern/kern_exit.c')
-rw-r--r-- | sys/kern/kern_exit.c | 121 |
1 files changed, 101 insertions, 20 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 75ab0e9..2c9e2e4 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -30,11 +30,16 @@ #include <sys/proc.h> #include <sys/sched.h> #include <sys/syslog.h> +#include <sys/panic.h> +#include <sys/filedesc.h> +#include <sys/vnode.h> +#include <dev/cons/cons.h> #include <vm/physmem.h> #include <vm/dynalloc.h> #include <vm/vm.h> #include <vm/map.h> #include <machine/pcb.h> +#include <machine/cpu.h> #define pr_trace(fmt, ...) kprintf("exit: " fmt, ##__VA_ARGS__) #define pr_error(...) pr_trace(__VA_ARGS__) @@ -48,6 +53,11 @@ unload_td(struct proc *td) struct pcb *pcbp; size_t len; + sched_detach(td); + if (ISSET(td->flags, PROC_KTD)) { + return; + } + execp = &td->exec; auxvalp = &execp->auxval; pcbp = &td->pcb; @@ -72,56 +82,127 @@ unload_td(struct proc *td) } } +void +proc_reap(struct proc *td) +{ + struct pcb *pcbp; + struct filedesc *fdp; + vaddr_t stack_va; + paddr_t stack_pa; + + cons_detach(); + + /* Clear out all fds */ + for (size_t i = 4; i < PROC_MAX_FILEDES; ++i) { + fdp = td->fds[i]; + if (fdp == NULL) { + continue; + } + if (fdp->refcnt == 1) { + vfs_release_vnode(fdp->vp); + dynfree(fdp); + fdp = NULL; + } + } + + pcbp = &td->pcb; + unload_td(td); + + /* + * User space stacks are identity mapped and + * kernel space stacks are not. + */ + if (ISSET(td->flags, PROC_KTD)) { + stack_va = td->stack_base; + stack_pa = td->stack_base - VM_HIGHER_HALF; + } else { + stack_va = td->stack_base; + stack_pa = td->stack_base; + vm_unmap(pcbp->addrsp, stack_va, PROC_STACK_SIZE); + } + + vm_free_frame(stack_pa, PROC_STACK_PAGES); + pmap_destroy_vas(pcbp->addrsp); +} + /* * Kill a thread and deallocate its resources. * * @td: Thread to exit */ int -exit1(struct proc *td) +exit1(struct proc *td, int flags) { - struct pcb *pcbp; - struct proc *curtd; - uintptr_t stack; + struct proc *curtd, *procp; + struct proc *parent; + struct cpu_info *ci; pid_t target_pid, curpid; + if (td->pid == 1) { + panic("init died\n"); + } + + ci = this_cpu(); target_pid = td->pid; curtd = this_td(); - pcbp = &td->pcb; curpid = curtd->pid; - stack = td->stack_base; td->flags |= PROC_EXITING; + parent = td->parent; - /* - * If this is on the higher half, it is kernel - * mapped and we need to convert it to a physical - * address. - */ - if (stack >= VM_HIGHER_HALF) { - stack -= VM_HIGHER_HALF; + /* If we have any children, kill them too */ + if (td->nleaves > 0) { + TAILQ_FOREACH(procp, &td->leafq, leaf_link) { + if (!ISSET(procp->flags, PROC_EXITING)) + exit1(procp, flags); + } } - unload_td(td); - vm_unmap(pcbp->addrsp, td->stack_base, PROC_STACK_SIZE); - vm_free_frame(stack, PROC_STACK_PAGES); + if (target_pid != curpid) { + proc_reap(td); + } - pmap_destroy_vas(pcbp->addrsp); - dynfree(td); + if (td->data != NULL) { + dynfree(td->data); + } + + /* + * Only free the process structure if we aren't + * being waited on, otherwise let it be so the + * parent can examine what's left of it. + */ + if (!ISSET(td->flags, PROC_WAITED)) { + dynfree(td); + } else { + td->flags |= PROC_ZOMB; + td->flags &= ~PROC_WAITED; + } /* * If we are the thread exiting, reenter the scheduler * and do not return. */ - if (target_pid == curpid) + if (target_pid == curpid) { + ci->curtd = NULL; + if (parent->pid == 0) + sched_enter(); + + parent->flags &= ~PROC_SLEEP; sched_enter(); + } return 0; } +/* + * arg0: Exit status. + */ scret_t sys_exit(struct syscall_args *scargs) { - exit1(this_td()); + struct proc *td = this_td(); + + td->exit_status = scargs->arg0; + exit1(td, 0); __builtin_unreachable(); } |