快捷搜索:

linux进程管理之进程的退出(1)

在进程运行停止后,我们会显示的调用exit()或者return退出正在运行的进程,假如调用return的话,编译器会自己加上exit().此时,保存子进程的一部份信息是很有需要的,由于父进程可以读取这些消息而取得子进程的退出状态.假如子进程退出.但父进程没有用wait(),这就成为了我们常说的僵尸进程,exit()系统调用在内核中的响应接口为sys_exit(),我们来跟踪一下,看下内核是若何处置惩罚这个历程的,

fastcall 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));

//弗成以在中断高低文或者是0号进程应用该函数

if (unlikely(in_interrupt()))

panic("Aiee, killing interrupt handler!");

if (unlikely(!tsk->pid))

panic("Attempted to kill the idle task!");

//假如定义了PT_TRACE_EXIT.进程通出时,发出告示

if (unlikely(current->ptrace & PT_TRACE_EXIT)) {

current->ptrace_message = code;

ptrace_notify((PTRACE_EVENT_EXIT 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;

if (tsk->io_context)

exit_io_context();

set_current_state(TASK_UNINTERRUPTIBLE);

schedule();

}

//设置PF_EXITING:表示进程正在退出

tsk->flags |= PF_EXITING;

/*

* tsk->flags are checked in the futex code to protect against

* an exiting task cleaning up the robust pi futexes.

*/

smp_mb();

spin_unlock_wait(&tsk->pi_lock);

if (unlikely(in_atomic()))

printk(KERN_INFO "note: %s[%d] exited with preempt_count %dn",

current->comm, task_pid_nr(current),

preempt_count());

acct_update_integrals(tsk);

if (tsk->mm) {

update_hiwater_rss(tsk->mm);

update_hiwater_vm(tsk->mm);

}

//tsk->signal->live:进程组中的进程数

//假如&tsk->signal->live -1为零返回为真

group_dead = atomic_dec_and_test(&tsk->signal->live);

if (group_dead) {

exit_child_reaper(tsk);

hrtimer_cancel(&tsk->signal->real_timer);

exit_itimers(tsk->signal);

}

acct_collect(code, group_dead);

#ifdef CONFIG_FUTEX

if (unlikely(tsk->robust_list))

exit_robust_list(tsk);

#ifdef CONFIG_COMPAT

if (unlikely(tsk->compat_robust_list))

compat_exit_robust_list(tsk);

#endif

#endif

if (group_dead)

tty_audit_exit();

if (unlikely(tsk->audit_context))

audit_free(tsk);

//退出状态码

tsk->exit_code = code;

taskstats_exit(tsk, group_dead);

//退出进程所占用的空间

exit_mm(tsk);

if (group_dead)

acct_process();

//从进程的旌旗灯号从IPC行列步队中删除

exit_sem(tsk);

//

__exit_files(tsk);

//关闭打开的文件

__exit_fs(tsk);

check_stack_usage();

exit_thread();

cgroup_exit(tsk, 1);

exit_keys(tsk);

//进程组整个退出且当提高程是进程组的组长

if (group_dead && tsk->signal->leader)

//离开当前的tty 并向进程显示终真个组发送SIGHUP 和SIGCONT

disassociate_ctty(1);

//削减模块的引用计数

module_put(task_thread_info(tsk)->exec_domain->module);

if (tsk->binfmt)

module_put(tsk->binfmt->module);

proc_exit_connector(tsk);

//更新进程的支属关系.并给父进程发送响应的旌旗灯号

exit_notify(tsk);

#ifdef CONFIG_NUMA

mpol_free(tsk->mempolicy);

tsk->mempolicy = NULL;

#endif

#ifdef CONFIG_FUTEX

/*

* This must happen late, after the PID is not

* hashed anymore:

*/

if (unlikely(!list_empty(&tsk->pi_state_list)))

exit_pi_state_list(tsk);

if (unlikely(current->pi_state_cache))

kfree(current->pi_state_cache);

#endif

/*

* Make sure we are holding no locks:

*/

//Debug函数

debug_check_no_locks_held(tsk);

/*

* 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.

*/

//进程退出已经完成了,设置PF_EXITPIDONE

tsk->flags |= PF_EXITPIDONE;

if (tsk->io_context)

exit_io_context();

if (tsk->splice_pipe)

__free_pipe_info(tsk->splice_pipe);

preempt_disable();

/* causes final put_task_struct in finish_task_switch(). */

//设置进程的状态为TASK_DEAD

tsk->state = TASK_DEAD;

//调整另一个进程运行

schedule();

BUG();

/* Avoid "noreturn function does return". */

for (;;)

cpu_relax();     /* For when BUG is null */

}

这个函数涉及到很多的子系统,我们暂时只阐发跟内存相关的部份.do_exit()不参在中断高低文中应用,不能在0号进程中应用.由于这个函数很开释进程的所占用的空间.假如在中断或者是0号进程中删除进程的资本,将会造成劫难性的后果.

开释进程所占用的空间的操作是在exit_mm()中完成的.对应的代码如下所示:

static void exit_mm(struct task_struct * tsk)

{

struct mm_struct *mm = tsk->mm;

mm_release(tsk, mm);

if (!mm)

return;

down_read(&mm->mmap_sem);

if (mm->core_waiters) {

up_read(&mm->mmap_sem);

down_write(&mm->mmap_sem);

if (!--mm->core_waiters)

complete(mm->core_startup_done);

up_write(&mm->mmap_sem);

wait_for_completion(&mm->core_done);

down_read(&mm->mmap_sem);

}

atomic_inc(&mm->mm_count);

BUG_ON(mm != tsk->active_mm);

/* more a memory barrier than a real lock */

task_lock(tsk);

tsk->mm = NULL;

up_read(&mm->mmap_sem);

enter_lazy_tlb(mm, current);

/* We don't want this task to be frozen prematurely */

clear_freeze_flag(tsk);

task_unlock(tsk);

mmput(mm);

}

您可能还会对下面的文章感兴趣: