NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; int group_dead; profile_task_exit(tsk); WARN_ON(atomic_read(&tsk->fs_excl)); //如果进程holding fs exclusive resources,则报错。但是还是不理解这个字段的作用 WARN_ON(blk_needs_flush_plug(tsk));//保证task_struct中的plug字段是空的,或者plug字段指向的队列是空的。plug字段的意义是stack plugging if (unlikely(in_interrupt())) //中断服务程序是不应该调用do_exit的,因此要对其进行检查。 panic("Aiee, killing interrupt handler!"); if (unlikely(!tsk->pid)) //不能杀死idle进程和init进程。 panic("Attempted to kill the idle task!"); /* * If do_exit is called because this processes oopsed, it's possible * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before * continuing. Amongst other possible reasons, this is to prevent * mm_release()->clear_child_tid() from writing to a user-controlled * kernel address. */ set_fs(USER_DS); //fs寄存器指向当前活动线程的TEB结构(线程结构)???? tracehook_report_exit(&code); // possibly stop for a ptrace event notification validate_creds_for_do_exit(tsk); //check creds for do_exit().我们现在先不关心credential机制。 /* * We're taking recursive faults here in do_exit. Safest is to just * leave this task alone and wait for reboot. */ if (unlikely(tsk->flags & PF_EXITING)) { printk(KERN_ALERT "Fixing recursive fault but reboot is needed!\n"); /* * We can do this unlocked here. The futex code uses * this flag just to verify whether the pi state * cleanup has been done or not. In the worst case it * loops once more. We pretend that the cleanup was * done as there is no way to return. Either the * OWNER_DIED bit is set by now or we push the blocked * task into the wait for ever nirwana as well. */ tsk->flags |= PF_EXITPIDONE; //该进程正在被 set_current_state(TASK_UNINTERRUPTIBLE); schedule(); } exit_irq_thread(); /* * Set the THREAD DIED flag to prevent further wakeups of the * soon to be gone threaded handler. */ exit_signals(tsk); /* sets PF_EXITING *//*以后再讨论信号量的事情*/ /* * tsk->flags are checked in the futex code to protect against * an exiting task cleaning up the robust pi futexes. */ smp_mb(); raw_spin_unlock_wait(&tsk->pi_lock); if (unlikely(in_atomic())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", current->comm, task_pid_nr(current), preempt_count()); acct_update_integrals(tsk); //update mm integral fields in task_struct.不过看源代码好像主要是设置task_struct中与时间相关的选项。 /* sync mm's RSS info before statistics gathering */ if (tsk->mm) sync_mm_rss(tsk, tsk->mm); //这个函数实现的机制并没有搞清楚,确切得说是没有搞清楚rss机制。 group_dead = atomic_dec_and_test(&tsk->signal->live); if (group_dead) { hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); if (tsk->mm) setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm); } acct_collect(code, group_dead); //collect accounting information into pacct_struct. if (group_dead) tty_audit_exit(); if (unlikely(tsk->audit_context)) audit_free(tsk); tsk->exit_code = code; taskstats_exit(tsk, group_dead); //Send pid data out on exit exit_mm(tsk); //放弃进程占用的mm,如果没有其他进程使用该mm,则释放它。
if (group_dead) acct_process(); trace_sched_process_exit(tsk); e
进程管理之exit()
最新推荐文章于 2022-10-10 20:07:01 发布
本文详细探讨了进程管理中exit()函数的关键步骤,重点解析了exit_mm过程,包括mm_release()用于处理vfork创建进程的特殊情况,以及put_mm()如何释放页面、页目录等资源。同时,解释了为何不释放task_struct结构的原因,以防止内核存储空间泄露。
摘要由CSDN通过智能技术生成