实验六:fork函数对应的系统调用处理过程

钟晶晶+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

一.实验过程

 

b sys_clone
b do_fork
b dup_task_struct
b copy_process
b copy_thread
b ret_from_fork

 

跟踪到do_fork

 跟踪到copy_process

 跟踪到copy_thread

到此就一直在循环执行,最后执行到ret_from_fork.在ret_from_fork中会jump到syscall_exit。

 

二. 实验分析

Linux通过复制父进程创建新进程,fork、vfork、clone都是通过do_exit实现进程的创建。

-A.复制一个PCB

-B.给新进程分配一个新的内核堆栈(复制了thread_info,不是复制了内核堆栈)

-C.修改复制的数据,即子进程初始化。

在start_kernel中,创建了0号进程,0号进程创建了1号进程,1号进程是所有用户态进程的祖先,0号进程是所有内核进程的祖先。之后其他进程都通过clone(),fork(),vfork()创建,是0号或1号的子孙进程。创建新进程通过复制父进程实现,先复制task_struct,再为其分配一个内核栈,然后修改需要改动的地方,比如进程pid,进程链表等等。

创建好之后,会跳转到ret_from_fork,在ret_from_fork中会jmp到syscall_exit,此时父进程的内核栈中保存了父进程在执行fork()前的上下文。子进程的内核栈中也从父进程那里拷贝得到了自己的上下文。所以它们现在只有被调度到,都可以正常的执行。

接下来可能发生进程调度,如果子进程得到CPU,就可以正常执行,父进程得到CPU也可以正常执行。

 

三.特别关注新进程是从哪里开始执行的?为什么从哪里能顺利执行下去?即执行起点与内核堆栈如何保证一致

   新进程从ret_from_fork开始执行;决定了新进程的第一条指令地址。

  • 在ret_from_fork之前,也就是在copy_thread()函数中childregs = current_pt_regs();该句将父进程的regs参数赋值到子进程的内核堆栈,
  • *childregs的类型为pt_regs,里面存放了SAVE ALL中压入栈的参数
  • 故在之后的RESTORE ALL中能顺利执行下去
posted @ 2017-04-01 13:21  yingtaotao  阅读(537)  评论(0)    收藏  举报