进程管理1

来源:互联网 发布:阿里云股票数据接口 编辑:程序博客网 时间:2024/06/16 02:20

1.进程简介

进程事处于执行器的程序。

程序本身并不是进程,进程是处于执行期的程序以及相关资源的总称。

linux内核中,调用fork来创建进程,fork()实际上是由clone实现的。

在现代操作系统中,进程提供两种虚拟机制:虚拟处理器和虚拟内存。

2.进程的状态:

进程有五种状态:TASK_RUNNING,TASK_INTERRUPTIBLE,TASK_UNINTERRUPTIBLE,_TASK_TRACED,_TASK_STOPPED

其中的切换情况如下图。

3.进程创建

linux通过clone系统调用实现fork。然后clone去调用do_fork。然后由do_fork完成创建中的大部分工作,该函数调用copy_process函数。

copy_process函数的过程:

       1.调用dup_task_struct为新进程创建一个内核栈、thread_info结构和task_struct,这些值与当前进程的值相同。此时,子进程和父进程的描述符是完全相同的。

       2.检查并确保新创建的子进程后,当前用户所拥有的进程数目没有超出给它分配的资源的限制

       3.子进程着手使自己和父进程区别开来。进程描述符内的许多成员都要被清0或者设为初始值。那些不是继承而来的进程描述符成员,主要是统计信息。task_struct中的大多数数据依然未被修改。

       4.子进程的状态被设置为TASK_UNINTERRUPTIBLE,以保证它不会投入使用

       5.copy_process调用copy_flags以更新task_struct的flags成员。表明进程是否拥有超级用户权限的PF_SUPERPRIV的标志被清0.表明进程还没有调用exec函数的PF_FORKNOEXEC标志被设置。

       6.调用alloc_pid为新进程分配一个有效的PID

       7.根据传递给clone的参数标志,copy_process拷贝或共享打开文件、文件系统信息、信号处理函数、进程地址空间和命名空间等。在一般情况下,这些资源会被给定进程的所有线程共享;否则,这些资源对每个进程是不同的,因此被拷贝到这里。

      8.最后copy_process做扫尾工作并返回一个指向子进程的指针。


4.进程终结

 进程终结大部分是靠do_exit(定义于kernel/exit.c)来完成。

              1.将task_struct中的标志成员设置为PF_EXITING.

              2.调用del_timer_sync删除任一内核定时器。根据返回的结构,它确保没有定时器在排队,也没有定时器处理程序在运行。

              3.如果BSD的进程记账功能是开启的,do_exit调用acct_update_integrals来输出记账信息。

      4.然后调用exit_mm函数释放进程占用的mm_struct,如果没有别的进程使用它们,就彻底释放它们

      5.接下来调用sem_exit,如果进程排队等候IPC信号,它则离开队列

      6.调用exit_files,和exit_fs,以分别递减文件描述符、文件系统数据的引用计数。如果其中某个引用计数的数值降为零,那么就代表没有进程在使用相应的资源,此时可以释放。

        7.接着把存放在task_struct的exit_code成员中的任务退出代码为由exit提供的退出代码,或者去完成任何其他由内核机制规定的退出动作。退出代码存放在这里由父进程随时检索。

     8.调用exit_notify向父进程发信号,给子进程重新寻找养父,养父为线程组中的其他进程或者init进程,并把进程状态设置为EXIT_ZOMBIE。

     9.do_exit调用schedule切换到新的进程。因为处于EXIT_ZOMBIE状态的进程不会再被调度,所以这时进程所直行的最后一段代码。do_exit永不返回。


进程终结时所需的清理工作和进程描述符的删除被分开执行。

进程描述符释放时,release_task会被调用,完成以下工作

1.它调用__exit_signal,该函数调用_unhash_process,后者又调用detach_pid从pidhash上删除该进程,同时也要从任务列表中删除该进程

2._exit_signal释放目前僵死进程所使用的所有剩余资源,并进程最终统计和记录

3.如果这个进程时线程组的最后一个进程,并且零头进程已经死掉,那么release_task就要通知僵死的领头进程的父进程。

4.release_task调用put_task_struct释放进程内核栈和thread_info结构所占的页,并释放task_struct所占的slab高速缓存。


















原创粉丝点击