diff options
Diffstat (limited to 'sys/kern/kern_exit.c')
-rw-r--r-- | sys/kern/kern_exit.c | 113 |
1 files changed, 93 insertions, 20 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index d6c9168..af697d7 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -30,15 +30,24 @@ #include <sys/proc.h> #include <sys/sched.h> #include <sys/syslog.h> +#include <sys/atomic.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__) +extern volatile size_t g_nthreads; +extern struct proc g_init; + static void unload_td(struct proc *td) { @@ -49,6 +58,10 @@ unload_td(struct proc *td) size_t len; sched_detach(td); + if (ISSET(td->flags, PROC_KTD)) { + return; + } + execp = &td->exec; auxvalp = &execp->auxval; pcbp = &td->pcb; @@ -73,47 +86,92 @@ 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, *procp; - uintptr_t stack; + 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; + + /* We have one less process in the system! */ + atomic_dec_64(&g_nthreads); - /* If we have any children, kill them too */ + /* Reassign children to init */ if (td->nleaves > 0) { TAILQ_FOREACH(procp, &td->leafq, leaf_link) { - exit1(procp); + procp->parent = &g_init; } } - /* - * 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 (target_pid != curpid) { + proc_reap(td); } - unload_td(td); - vm_unmap(pcbp->addrsp, td->stack_base, PROC_STACK_SIZE); - vm_free_frame(stack, PROC_STACK_PAGES); - pmap_destroy_vas(pcbp->addrsp); + if (td->data != NULL) { + dynfree(td->data); + } /* * Only free the process structure if we aren't @@ -124,14 +182,29 @@ exit1(struct proc *td) 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) { + /* + * If the thread is exiting on a core that is not + * preemptable, something is not right. + */ + if (__unlikely(!sched_preemptable())) { + panic("exit1: cpu %d not preemptable\n", ci->id); + } + + ci->curtd = NULL; + if (parent->pid == 0) + sched_enter(); + + parent->flags &= ~PROC_SLEEP; sched_enter(); + } return 0; } @@ -145,6 +218,6 @@ sys_exit(struct syscall_args *scargs) struct proc *td = this_td(); td->exit_status = scargs->arg0; - exit1(td); + exit1(td, 0); __builtin_unreachable(); } |