有两个点:从RUNNING到ZOMBIE到DEAD的状态转换;另外一个就是通知父进程届时删除进程描述符.
sys_exit
=>do_exit((error_code&0xff)<<8);
=>tsk->flags |= PF_EXITING;
=>tsk->exit_code = code;
=>exit_mm(tsk);
=>mm_release(tsk, mm);
=>if (vfork_done) {
tsk->vfork_done = NULL;
complete(vfork_done);
}
=>tsk->mm = NULL;
=>mmput(mm);
=>if (atomic_dec_and_test(&mm->mm_users))
exit_aio(mm);
exit_mmap(mm);
=>munlock_vma_pages_all(vma);
=>tlb = tlb_gather_mmu(mm, 1);
=>end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
=>free_pgtables(tlb, vma, FIRST_USER_ADDRESS, 0);//清除页表
=>tlb_finish_mmu(tlb, 0, end);
if (!list_empty(&mm->mmlist))
list_del(&mm->mmlist);
mmdrop(mm);
=>__exit_files(tsk);
=>if (files)
tsk->files = NULL;
tsk->files = NULL;
=>__exit_fs(tsk);
=>exit_thread();
=>cpuset_exit(tsk);
=>module_put(task_thread_info(tsk)->exec_domain->module);
=>if (tsk->binfmt)
module_put(tsk->binfmt->module);
=>exit_task_namespaces(tsk);
=>exit_notify(tsk);//向父进程发送exit信号,父进程可以释放其进程描述符
=>if (tsk->exit_signal != -1 && thread_group_empty(tsk)) {
int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD;
do_notify_parent(tsk, signal);
=>info.si_signo = sig;
info.si_errno = 0;
info.si_pid = tsk->pid;
info.si_uid = tsk->uid;
=>info.si_status = tsk->exit_code & 0x7f;
if (tsk->exit_code & 0x80)
info.si_code = CLD_DUMPED;
else if (tsk->exit_code & 0x7f)
info.si_code = CLD_KILLED;
else {
info.si_code = CLD_EXITED;
info.si_status = tsk->exit_code >> 8;
}
psig = tsk->parent->sighand;
=>if (valid_signal(sig) && sig > 0)
__group_send_sig_info(sig, &info, tsk->parent);//发信号给父进程
=>__wake_up_parent(tsk, tsk->parent);//唤醒父进程
} else if (tsk->ptrace) {
do_notify_parent(tsk, SIGCHLD);
}
=>write_lock_irq(&tasklist_lock);//关中断,防止下面的流程被中断打断,如果被打断就调度出去回不来了
=>state = EXIT_ZOMBIE;//再也没机会被schedule选中而获取CPU资源
=>if (tsk->exit_signal == -1 && likely(!tsk->ptrace))
state = EXIT_DEAD;
=>tsk->exit_state = state;
=>write_unlock_irq(&tasklist_lock);//开中断,可以被打断了
=>if (state == EXIT_DEAD)
release_task(tsk);
=>tsk->flags |= PF_EXITPIDONE;
=>preempt_disable();
=>tsk->state = TASK_DEAD;
=>schedule();//调度出去,再也回不来,如果回来了,那很不受待见,出问题了
=>BUG();
=>for (;;)
cpu_relax();
do_group_exit会杀死进程组所有进程,里面调用函数zap_other_threads
/*
* Nuke all other threads in the group.
*/
void zap_other_threads(struct task_struct *p)
{
struct task_struct *t;
p->signal->group_stop_count = 0;
/*通过for循环可以看到如何找到一个线程组的所有子线程*/
for (t = next_thread(p); t != p; t = next_thread(t)) {
/*
* Don't bother with already dead threads
*/
if (t->exit_state)
continue;
/* SIGKILL will be handled before any pending SIGSTOP */
//*所有线程都将执行do_exit函数*/
sigaddset(&t->pending.signal, SIGKILL);
signal_wake_up(t, 1);
}
}
参考学习文章
UNIX再学习 -- exit 和 wait 系列函数
https://blog.youkuaiyun.com/qq_29350001/article/details/70255915