本文为我学习linux内核的总结。

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

1、概述

  前面分析了系统调用的原理和过程。本文分析fork这个系统调用,重点分析进程的创建主要动作和流程。

2、fork 系统调用的主要动作

  

  如上图,fork、vfork、clone,最终都是调用do_fork。不过他们之间的差异也可以在do_fork及后续代码中看到,不过这里不讲述。

      do_fork 的主要逻辑为调用copy_process,又函数名就可以看到进程的生成逻辑就在copy_process.

  copy_process主要调用了:

        dup_task_struct()——主要是创建和复制进程

         copy_fs            ——拷贝文件句柄之类的

  copy_files         ——拷贝文件句柄之类的

        copy_mm         ——拷贝虚拟内存

  copy_io             ——拷贝io

  copy_thread     ——拷贝thead_info信息

       下面我们着重分析 dup_task_struct 和 copy_thread 。    

     2.1 、dup_task_struct:申请内存,拷贝task_struct和thread_info       

  如上图所示,前面两个调用为申请task_struct、thread_info 的内存,arch_dup_task_struct就是将父进程的

  task_struct 拷贝给子进程。

       setup_thread_stack:这个函数是将父进程的堆栈thread_info拷贝给子进程。

  

   2.2、copy_thread :准备栈信息

 如上图信息childregs保存父进程的堆栈信息,然后赋值给子进程堆栈。右图pt_regs为系统调用开始通过save_all保存的信息。

同时可以看到如果是内核创建线程走的不同的分支,不同的处理。

上面可以看到childregs->ax=0,就是返回值,也就是子进程返回的pid为0的原因。

p->thread.ip = (unsigned long) ret_from_fork,前面设置了sp栈顶,这里再设置ip。

ret_from_fork->syscall_exit。这里就很熟悉了,就是我们上一篇博客中的系统调用完成后的执行过程,ip为子进程执行的起点,所以可以知道
子进程开始调度时是从ret_from_fork开始执行的。
2.3、父进程

如上图所示,子进程完全准备完毕,获取子进程id作用父进程的返回值,同时唤醒子进程。这样两个进程都可以运行了 。

3、debug

  下面我们来跟踪fork内核执行过程,我们断住主要函数do_fork、copy_process、dup_task_struct、copy_thread 、

ret_from_fork

4、总结

  fork创建一个进程,实际上就将父进程的进程信息拷贝给子进程,子进程的起点就是父进程系统调用结束的位置。只有子进程信息完全准备好后,父进程要返回前才唤醒子进程。