/* * Cause the current thread to exit. * * We clean up the parts of the thread structure we don't actually * need to run right away. The rest has to wait until thread_destroy * gets called from exorcise(). */ void thread_exit(int exitcode) { DEBUG(DB_THREADS,"Thread %s exiting with %d", curthread->t_name, exitcode); /* ASST1: Let the pid management system know this thread is done. */ pid_setexited(curthread->t_pid, exitcode); if (curthread->t_stack != NULL) { /* * Check the magic number we put on the bottom end of * the stack in thread_fork. If these assertions go * off, it most likely means you overflowed your stack * at some point, which can cause all kinds of * mysterious other things to happen. */ assert(curthread->t_stack[0] == (char)0xae); assert(curthread->t_stack[1] == (char)0x11); assert(curthread->t_stack[2] == (char)0xda); assert(curthread->t_stack[3] == (char)0x33); } splhigh(); if (curthread->t_vmspace) { /* * Do this carefully to avoid race condition with * context switch code. */ struct addrspace *as = curthread->t_vmspace; curthread->t_vmspace = NULL; as_destroy(as); } if (curthread->t_cwd) { VOP_DECREF(curthread->t_cwd); curthread->t_cwd = NULL; } /* A3 SETUP */ if (curthread->t_filetable) { filetable_destroy(curthread->t_filetable); /* set it back to NULL so it can be initialized again */ curthread->t_filetable = NULL; } /* END A3 SETUP */ assert(numthreads>0); numthreads--; mi_switch(S_ZOMB); panic("Thread came back from the dead!\n"); }
/* * Destroy a proc structure. * * Note: nothing currently calls this. Your wait/exit code will * probably want to do so. */ void proc_destroy(struct proc *proc) { /* * You probably want to destroy and null out much of the * process (particularly the address space) at exit time if * your wait/exit design calls for the process structure to * hang around beyond process exit. Some wait/exit designs * do, some don't. */ KASSERT(proc != NULL); KASSERT(proc != kproc); /* * We don't take p_lock in here because we must have the only * reference to this structure. (Otherwise it would be * incorrect to destroy it.) */ /* VFS fields */ if (proc->p_cwd) { VOP_DECREF(proc->p_cwd); proc->p_cwd = NULL; } if (proc->p_filetable) { filetable_destroy(proc->p_filetable); proc->p_filetable = NULL; } /* VM fields */ if (proc->p_addrspace) { /* * If p is the current process, remove it safely from * p_addrspace before destroying it. This makes sure * we don't try to activate the address space while * it's being destroyed. * * Also explicitly deactivate, because setting the * address space to NULL won't necessarily do that. * * (When the address space is NULL, it means the * process is kernel-only; in that case it is normally * ok if the MMU and MMU- related data structures * still refer to the address space of the last * process that had one. Then you save work if that * process is the next one to run, which isn't * uncommon. However, here we're going to destroy the * address space, so we need to make sure that nothing * in the VM system still refers to it.) * * The call to as_deactivate() must come after we * clear the address space, or a timer interrupt might * reactivate the old address space again behind our * back. * * If p is not the current process, still remove it * from p_addrspace before destroying it as a * precaution. Note that if p is not the current * process, in order to be here p must either have * never run (e.g. cleaning up after fork failed) or * have finished running and exited. It is quite * incorrect to destroy the proc structure of some * random other process while it's still running... */ struct addrspace *as; if (proc == curproc) { as = proc_setas(NULL); as_deactivate(); } else { as = proc->p_addrspace; proc->p_addrspace = NULL; } as_destroy(as); } threadarray_cleanup(&proc->p_threads); spinlock_cleanup(&proc->p_lock); kfree(proc->p_name); kfree(proc); }