内核版本:linux-4.4.18
源码位置:这里

fork相关的代码最终执行的函数为_do_fork(),下面按照顺序分析下_do_fork()

  • 首先判断是否需要trace(跟踪)这个进程,这一步主要与调试相关,GDB在x86-64 Linux 系统上的原理就是利用ptrace(2)系统调用 [1]。

    • 有关likelyUnlikely,实际上是利用gcc内置函数对分支条件的优化 [2]。

      if (likely(!ptrace_event_enabled(current, trace))) // likely表示大多数情况下下面分支会被执行
      trace = 0;
  • 接着代码调用copy_process(),它设置了进程描述符以及子进程所需的任何其他内核数据结构。

    • 它的参数和_do_fork()相比增加了一个子进程的pid
    • 接下来检查clone_flags参数中传递的标志是否兼容。
    • 通过调用security_task_create()来执行额外的安全检查。
    • 调用dup_task_struct(),为新进程创建新的内核堆栈,thread_infotask_struct结构。
      • 执行alloc_task_struct_node()获得新进程的task_struct结构,并将其地址存储在tsk局部变量中。
      • 执行alloc_thread_info_node()获得一个空闲的内存区域来存储新进程的thread_info结构。
      • 执行arch_dup_task_struct()将父进程的信息复制到tsk变量中,实际上是调用memecpy(),然后将tsk->stack设置为ti。
      • 将当前的thread_info描述符的内容复制到tsk->stack所指向的结构中。
      • atomic_set(&tsk->usage, 2),usage字段表示task_struct的引用计数[3]。
    • ftrace_graph_init_task()初始化ftrace,内核追踪函数调用。
    • rt_mutex_init_task()初始化锁。
    • copy_creds(p, clone_flags)拷贝父进程的信号。
    • if (nr_threads >= max_threads)检查当前用户的最大线程数是否大于max_thread
    • PF_SUPERPRIV标志判断此任务是否使用超级用户权限,PF_FORKNOEXEC表示进程没有调用exec
    • 调用init_sigpending()来清除挂起的信号。
    • 调用sched_fork()来分割父子进程之间的剩余时间片,将子进程状态置为TASK_RUNNING,代码见这里
    • 接下来拷贝所有的进程信息(files、fs、sighand、signal、mm、namespaces、io、thread_tls)。
    • alloc_pid()分配新的Pid。
    • copy_thread_tls()函数里面将寄存器%ax置为0,也是子进程pid返回0的原因,代码点这里
    • 做一些清理等工作,返回task_struct
  • 如果返回值没有错误,调用wake_up_new_task将进程插入运行队列,此时状态为TASK_RUNNING

  • 如果指定了CLONE_VFORK标志,它会先让子进程运行。

  • 返回子进程的pid。

参考文献
[1] GDB的基本工作原理
[2] 关于likely()与unlikely函数
[3] Understanding the structure task_struct

Linux内核 fork 源码分析的更多相关文章

  1. Linux 内核网桥源码分析

    Linux网桥源码的实现 转自: Linux二层网络协议 Linux网桥源码的实现 1.调用 在src/net/core/dev.c的软中断函数static void net_rx_action(st ...

  2. linux调度器源码分析 - 运行(四)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 之前的文章已经将调度器的数据结构.初始化.加入进程都进行了分析,这篇文章将主要说明调度器是如何在程序稳定运 ...

  3. linux调度器源码分析 - 初始化(二)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 上期文章linux调度器源码分析 - 概述(一)已经把调度器相关的数据结构介绍了一遍,本篇着重通过代码说明 ...

  4. Linux进程调度与源码分析(二)——进程生命周期与task_struct进程结构体

    1.进程生命周期 Linux操作系统属于多任务操作系统,系统中的每个进程能够分时复用CPU时间片,通过有效的进程调度策略实现多任务并行执行.而进程在被CPU调度运行,等待CPU资源分配以及等待外部事件 ...

  5. linux调度器源码分析 - 概述(一)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 调度器作为操作系统的核心部件,具有非常重要的意义,其随着linux内核的更新也不断进行着更新.本系列文章通 ...

  6. Linux进程调度与源码分析(一)——简介

    本系列文章主要是近期针对Linux进程调度源码进行阅读与分析后的经验总结,分析过程中可能结合部分Linux网络编程的相关知识以便于理解,加深对Linux进程调度的理解和知识分享. 本系列文章主要结合L ...

  7. Linux进程调度与源码分析(三)——do_fork()的实现原理

    用户层的fork(),vfork(),clone()API函数在执行时,会触发系统调用完成从用户态陷入到内核态的过程,而上述函数的系统调用,最终实现都是通过内核函数do_fork()完成,本篇着重分析 ...

  8. Linux network namespace源码分析

    一.network namespace的创建 在对iproute2的源码进行分析后,我们可以知道,当我们调用命令`ip netns add ns1`时,本质上就是调用`unshare(CLONE_NE ...

  9. PHP7内核:源码分析的环境与工具

    本文主要介绍分析源码的方式,其中包含环境的搭建.分析工具的安装以及源码调试的基本操作. 一.工具清单 PHP7.0.12 GDB CLion 二.源码下载及安装 $ wget http://php.n ...

随机推荐

  1. Java之SpringBoot自定义配置与整合Druid

    Java之SpringBoot自定义配置与整合Druid SpringBoot配置文件 优先级 前面SpringBoot基础有提到,关于SpringBoot配置文件可以是properties或者是ya ...

  2. Java基础系列(1)- JDK、JRE、JVM

    Java三大版本(Write Once:Run Anywhere) JavaSE:标准版 JavaME:嵌入式开发 JavaEE:E企业级开发 JDK.JRE.JVM JDK是开发工具包 JRE是编译 ...

  3. 送你一个Python 数据排序的好方法

    摘要:学习 Pandas排序方法是开始或练习使用 Python进行基本数据分析的好方法.最常见的数据分析是使用电子表格.SQL或pandas 完成的.使用 Pandas 的一大优点是它可以处理大量数据 ...

  4. 简述编写Django应用的基本步骤

    (1)创建项目,cd到一个你想要放置你代码的目录.Django -admin startproject mysite. Django project即一个Django项目实例需要的设置项的集合,包括数 ...

  5. Linux服务器时间同步配置

    Linux服务器时间同步配置   以CentOS7 做时间服务器,其他服务器(Centos 6.RHEL7)同步该服务器时间 RHEL 7.CentOS 7 默认的网络时间协议 为Chrony 本教程 ...

  6. bzoj4025-二分图【线段树分治,并查集】

    正题 题目链接:https://darkbzoj.tk/problem/4025 题目大意 \(n\)个点\(m\)条边,每条边会在一个\(T\)以内的时间段内出现,对于任意一个\(T\)以内的时刻求 ...

  7. P4770-[NOI2018]你的名字【SAM,线段树合并】

    正题 题目链接:https://www.luogu.com.cn/problem/P4770 题目大意 给出一个长度为\(n\)的字符串\(S\).\(q\)次询问给出一个串\(T\)和一个区间\([ ...

  8. Kotlin基础入门之必知必会,查漏补缺来一手~~~

    数据类型 Kotlin跟 java 相同,基本数据类型有八种 boolean,char,int,short,long,float,double,byte 类型 位宽 最小值 最大值 Short 16 ...

  9. 在你面前有一个n阶的楼梯,你一步只能上1阶或2阶。 请问,当N=11时,你可以采用多少种不同的方式爬完这个楼梯();当N=9时呢?

    在你面前有一个n阶的楼梯,你一步只能上1阶或2阶.请问,当N=11时,你可以采用多少种不同的方式爬完这个楼梯:当N=9时呢? 思路解析 ①台阶只有一级阶梯时,只有一种走法. ②当台阶有两级时,可以先走 ...

  10. 洛谷3176 [HAOI2015]数字串拆分 (矩阵乘法+dp)

    qwq真的是一道好题qwq自己做基本是必不可能做出来的. 首先,如果这个题目只是求一个\(f\)数组的话,那就是一道裸题. 首先,根据样例 根据题目描述,我们能发现其实同样数字的不同排列,也是属于不同 ...