Linux内核-进程管理

网友投稿 1019 2022-05-30

Linux内核-进程管理

1.进程

#内核调度的对象是线程,不是进程

#对Linux而言,线程只是特殊的进程

#进程提供两种虚拟机制:虚拟处理器、虚拟内存

#创建进程通过fork()来从父进程复制创建进程

2.进程描述符

#任务队列:双向链表(每一项都是task_struct--->进程描述符)

#Linux通过slab分配器分配task_struct

#内核通过唯一的进程标识值(PID)来标识进程

Linux内核-进程管理

#五种进程状态:  1.TASK_RUNNING 进程可执行

2.TASK_INTERRUPTIBLE 可中断

3.TASK_UNINTERRUPTIBLE 不可中断

4._TASK_TRACED 被其他进程跟踪

5._TASK_STOPPED 进程停止执行

#设置进程状态: set_task_state(task, state)函数和set_surrent_state(state)函数

#所有进程都是PID为1的init进程的后代

#init进程描述符 init_task

3.进程创建

#fork()和exec()

fork()拷贝当前进程创建子进程

exec()读入可执行文件并载入空间地址开始执行

#写时拷贝:fork()使用写时拷贝(copy-on-write)使得地址空间的页拷贝被推迟到实际发生写入时才进行

(fork()后立即执行exec()就无需进行拷贝)

fork()的实际开销就是复制父进程的页表以及分配进程描述符

#fork()执行过程:通过系统调用clone()调用fork()

clone()调用do_fork(),do_fork()调用copy_process()

copy_process()过程:

1.调用dum_task_struct()为新进程创建内核栈、thread_info、task_struct

2.确保创建子进程后当前进程数没有超过限制

3.子进程开始与父进程区别开来,进程描述符中的许多成员初始化或清0

4.子进程的状态被设置为TASK_UNINTERRUPTIBLE

5.调用copy_flags()更新来更新task_struct的flags成员

6.调用alloc_pid()为新进程分配PID

7.copy_process()拷贝共享打开的文件、文件系统信息、信号处理函数、进程地址空间和命名空间

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

#vfork():向clone()系统调用传递一个特殊标志来进行:

1.调用copy_process()时,task_struct的vfork_done成员被设置为NULL

2.如果执行do_fork()时给定地址,vfork_done会指向一个特定地址

3.子进程开始执行后,父进程不会立即开始执行,直到vfork_done指针向它发出信号

4.调用mm_release()进程退出地址空间,并检查vfork_done是否为空,若不为空,等待父进程发送信号

5.回到do_fork(),父进程醒来并返回

4.线程在Linux中的实现

#线程机制提供了在同一程序中共享内存地址的空间运行的一组线程

#Linux将所有的线程当做进程来实现

#创建线程:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND , 0)

5.进程终结

#发生在进程调用exit()系统调用时:

任务大部分要靠do_exit()来完成:

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()切换到新的进程

#删除进程描述符:调用了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所占的页

#孤儿进程造成的进退维谷:如果父进程在子进程之前退出,必须有机制保证子进程能找到新的父亲

Linux 任务调度

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:C语言中的.h头文件的作用
下一篇:如果你连业务领域建模都不会,那还怎么做架构师呢?
相关文章