一、目的

    本文将讲述进程是如何消亡的。一个进程既有父进程又有子进程,因此进程消亡时,既要通知父进程,也要安排好子进程。

    当前进程消亡时主要做了三件大事:释放当前进程占用的资源;为当前进程的子进程重新寻找“养父”;通知当前进程的父进程,释放当前进程剩下的资源。

    当前进程释放掉大多数进程资源后,只保留内核栈、structtask_struct数据结构;剩下的资源由父进程负责释放。

    linux调用sys_exit()sys_wait4()实现进程的消亡,代码可以在kernel/exit.c中找到。


二、当前进程释放自身资源

    当前进程使用sys_exit()->do_exit()释放进程占用的资源,处理过程如下:

    1、调用in_interrupt()检查中断服务程序是否调用了do_exit()(只有进程才能主动调用sys_exit(),中断服务程序在任何时候都不能调用do_exit());

    2、进程0不能消亡,因此检查当前进程的pid是否为0(即idle进程);

    3、调用exit_mm()释放内存地址空间;

    4、设置进程退出码,父进程将会获取;

    5、调用exit_mm()释放内存地址空间;

    6、如果进程排队等候IPC信号,则调用exit_sem()离开队列;

    7、调用exit_files()exit_fs()分别递减文件描述符、文件系统数据的引用计数;如果某个引用计数为零,则释放相应的资源;

    8、调用exit_task_namespaces()释放命名空间;

    9、调用check_stack_usage()检查进程内核栈的使用情况,并调用exit_thread()释放structthread_info结构体;

    10、调用exit_notify()->forget_original_parent()给当前进程的所有子进程按照以下规则重新寻找“养父”;

        a)如果当前进程是一个线程,养父为同一线程组中的下一个线程;

        b)养父是当前进程的祖先进程;

        c)养父是init进程;

    11、调用exit_notify()->do_notify_parent()向当前进程的养父发送信号,通知父进程当前进程即将消亡,让父进程来处理(父进程调用sys_waitpid释放剩下的资源)。


三、养父进程释放剩下的资源

    养父进程使用sys_waitpid()->sys_wait4()处理消亡的子进程,处理过程如下:

    1、在当前进程的栈中定义一个structwait_opts wo数据结构,重点关注wait_queue_tchild_wait成员;

    2、调用add_wait_queue()wochild_wait成员加入到当前进程的wait_chldexit队列中;

    3、设置当前进程的运行状态为可中断状态(INTERRUPTIBLE);

    4、如果子进程满足以下条件:

        a)子进程的状态为EXIT_DEAD,跳转到5);

        b)子进程的状态为EXIT_ZOMBIE,则调用wait_task_zombie()处理子进程消亡,跳转到5);

        c)子进程的状态为STOPPED,则调用wait_task_stopped()处理子进程的消亡,跳转到5);

        d)否则,调用wait_task_continued()继续执行;调用schedule()将当前进程睡眠,等到下一次被调度时,程序跳转到4)执行。

    5、设置当前进程的运行状态为TASK_RUNNING

    6、调用remove_wait_queue()child_waitwait_chldexit队列中移除。


四、总结

    进程消亡时,既要通知父进程,也要安排好子进程。


版权声明:

    原创作品,如非商业性转载,请注明出处;如商业性转载出版,请与作者联系。


Logo

更多推荐