分析Linux内核创建一个新进程的过程
郑斌 原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
实验要求:
- 阅读理解task_struct数据结构http://codelab.shiyanlou.com/xref/linux-3.18.6/include/linux/sched.h#1235;
- 分析fork函数对应的内核处理过程sys_clone,理解创建一个新进程如何创建和修改task_struct数据结构;
- 使用gdb跟踪分析一个fork系统调用内核处理函数sys_clone ,验证您对Linux系统创建一个新进程的理解,推荐在实验楼Linux虚拟机环境下完成实验。 特别关注新进程是从哪里开始执行的?为什么从那里能顺利执行下去?即执行起点与内核堆栈如何保证一致。
- 根据本周所学知识分析fork函数对应的系统调用处理过程,撰写一篇署名博客,并在博客文章中注明“真实姓名(与最后申请证书的姓名务必一致) + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”,博客内容的具体要求如下:
- 题目自拟,内容围绕对Linux系统如何创建一个新进程进行;
- 可以结合实验截图、绘制堆栈状态执行流程图等;
- 博客内容中需要仔细分析新进程的执行起点及对应的堆栈状态等。
- 总结部分需要阐明自己对“Linux系统创建一个新进程”的理解
实验环境:
本实验在实验楼Linux环境下完成。
实验步骤:
根据实验指导。我们先删除menu并clone以后 ,删除test_fork.c和test.c 后进行make rootfs。
MENUOS运行后help可以看到多了一个fork的功能。
当执行fork命令后,会输出相应的信息。
然后使用gdb进行调试。
我们在 sys_clone ,do_fork ,dup_task_struct , copy_process, copy_thread, ret_from_fork 等处设置断点。
1)程序首先执行到do_fork函数。
我们在http://codelab.shiyanlou.com/xref/linux-3.18.6/kernel/fork.c中看可以看到内核部分do_fork函数的相关代码。该函数功能为实现进程的创建。
如下图所示,注意到其中的copy_process()函数,也是gdb中下一处将要遇到的断点。
我们继续调试。
2)执行到copy_process。
该函数主要功能为拷贝进程信息。
在查看在copy_process内核代码中,定义了进程id、进程task_struct等信息。同时有p=dup_task_struct(current)。
复制当前的进程信息结构体给p,这里不妨猜测程序执行下一个遇到的断点为dup_task_struct。
3)执行到dup_task_struct函数。
4)接着依次执行到copy_thread函数。
可以看到有拷贝设置寄存器信息,esp,eip等内容。
5)然后是ret_from_fork。
这是子进程在内核中执行的起点。
之后就gdb跟踪不到了。
基于以上的分析,根据本人理解,新进程创建过程的执行流程图如下。
实验总结:
通过本次实验,学习了:
1进程控制块PCB---task_struct包括状态、描述符、打开的文件系统、标记、链表信息、内存管理、信号等等信息。
2Linux系统中,进程的状态在就绪和运行状态都是task_running状态。是否运行取决于是否在CPU的时序上运行,跟windows中类似,当等待事件发生或者资源分配等,进程变为阻塞状态, 事件发生或者等待的资源分配后转为就绪状态。
3Linux系统中进程是用一个双向循环链表的结构链接起来的。每个进程通过pid标识来区分。第一个进程创建后,当要创建新的进程,先复制父进程的内容,然后修改寄存器、标识符等信息。
4Linux系统中fork、vfork和clone三个系统调用都是通过调用do_fork来实现进程的创建。