/** * * Terminate the current process (maybe). If the current process has * more than one running thread, only terminate the current thread. * The process is only completely terminated (as per process_join * wakeup and page table deallocation) when the final thread calls * process_finish(). * * @param The return value of the process. This is only used when the * final thread exits. * */ void process_finish(int retval) { interrupt_status_t intr_status; thread_table_t *thread = thread_get_current_thread_entry(); process_id_t pid = thread->process_id; if (retval < 0) { /* Not permitted! */ retval = 0; } intr_status = _interrupt_disable(); spinlock_acquire(&process_table_slock); /* Mark the stack as free so new threads can reuse it. */ process_free_stack(thread); if (--process_table[pid].threads == 0) { /* We are the last thread - kill process! */ vm_destroy_pagetable(thread->pagetable); finish_given_process(pid, retval); } thread->pagetable = NULL; spinlock_release(&process_table_slock); _interrupt_set_state(intr_status); thread_finish(); }
void finish_given_process(process_id_t pid, int retval) { process_id_t parent = process_table[pid].parent; process_id_t zombie; process_table[pid].retval = retval; while ((zombie = process_table[pid].first_zombie) >= 0) { /* We have zombie children - remove them. */ process_table[zombie].state = PROCESS_FREE; process_table[zombie].retval = -1; process_table[zombie].parent = -1; process_table[pid].first_zombie = process_table[zombie].next_zombie; process_table[pid].children--; } if (parent >= 0 && process_table[parent].state == PROCESS_ZOMBIE) { /* We have a zombie parent, implying we can never be joined. */ if (--(process_table[parent].children) == 0 && process_table[parent].retval < 0) { /* Oh, and our parent is joined and we are the last child. so free our parent. */ finish_given_process(parent, 0); } process_table[pid].state = PROCESS_FREE; } else if (parent >= 0) { /* Our parent is alive and well, add us to its list of zombies */ process_table[pid].state = PROCESS_ZOMBIE; zombie = process_table[parent].first_zombie; process_table[pid].next_zombie = zombie; if (zombie >= 0) { process_table[zombie].prev_zombie = pid; } process_table[parent].first_zombie = pid; } else { /* We have no parent, i.e. we are the initial program, and will be joined by the startup thread in init/main.c */ process_table[pid].state = PROCESS_ZOMBIE; } sleepq_wake(&process_table[pid]); }
/** * * Terminate the current process (maybe). If the current process has * more than one running thread, only terminate the current thread. * The process is only completely terminated (as per process_join * wakeup and page table deallocation) when the final thread calls * process_finish(). * * @param The return value of the process. This is only used when the * final thread exits. * */ void process_finish(int retval) { interrupt_status_t intr_status; thread_table_t *thread = thread_get_current_thread_entry(); process_id_t pid = thread->process_id; if (retval < 0) { /* Not permitted! */ retval = 0; } intr_status = _interrupt_disable(); spinlock_acquire(&process_table_slock); vm_destroy_pagetable(thread->pagetable); finish_given_process(pid, retval); thread->pagetable = NULL; spinlock_release(&process_table_slock); _interrupt_set_state(intr_status); thread_finish(); }