fork 是linux创建进程的系统调用,相关的函数(不只是系统调用)还有 vfork,clone,sys_frok等。这些函数会整理不同参数,再调用到 do_fork 中。

本篇文章主要介绍do_fork 函数。(sys_call_table 是 系统调用表, fork -> syscall(number) -> sys_fork -> do_fork)

 1 /*
2 * Ok, this is the main fork-routine.
3 *
4 * It copies the process, and if successful kick-starts
5 * it and waits for it to finish using the VM if required.
6 */
7 long do_fork(unsigned long clone_flags,
8 unsigned long stack_start,
9 struct pt_regs *regs,
10 unsigned long stack_size,
11 int __user *parent_tidptr,
12 int __user *child_tidptr)
13 {
14 struct task_struct *p;
15 int trace = 0;
16 long pid;
17
18 if (unlikely(current->ptrace)) {
19 trace = fork_traceflag (clone_flags);
20 if (trace)
21 clone_flags |= CLONE_PTRACE;
22 }
23
24 p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr);
25 /*
26 * Do this prior waking up the new thread - the thread pointer
27 * might get invalid after that point, if the thread exits quickly.
28 */
29 pid = IS_ERR(p) ? PTR_ERR(p) : p->pid;
30
31 if (!IS_ERR(p)) {
32 struct completion vfork;
33
34 if (clone_flags & CLONE_VFORK) {
35 p->vfork_done = &vfork;
36 init_completion(&vfork);
37 }
38
39 if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {
40 /*
41 * We'll start up with an immediate SIGSTOP.
42 */
43 sigaddset(&p->pending.signal, SIGSTOP);
44 set_tsk_thread_flag(p, TIF_SIGPENDING);
45 }
46
47 p->state = TASK_STOPPED;
48 if (!(clone_flags & CLONE_STOPPED))
49 wake_up_forked_process(p); /* do this last */
50 ++total_forks;
51
52 if (unlikely (trace)) {
53 current->ptrace_message = pid;
54 ptrace_notify ((trace << 8) | SIGTRAP);
55 }
56
57 if (clone_flags & CLONE_VFORK) {
58 wait_for_completion(&vfork);
59 if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
60 ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
61 } else
62 /*
63 * Let the child process run first, to avoid most of the
64 * COW overhead when the child exec()s afterwards.
65 */
66 set_need_resched();
67 }
68 return pid;
69 }

18行:likely和unlikely是内核代码中常用的宏,likely实际是希望表达式x==1,即表达式x成立,并且在代码实际执行中,表达式x在绝大多数情况下是成立的,相反,unlikely是希望表达式在绝大多数情况下不成立。

24行: copy_process 复制进程信息。

31行: IS_ERR 是内核判断地址是否合法的常用函数。(具体为什么是(unsigned long)ptr > (unsigned long)-1000L,没太理解,chatgpt说是约定负数为错误,但个人感觉他说的不对。应该和地址空间有关(用户态占用3G内存,内核占用1G内存。))

34行: CLONE_VFORK  // set if the parent wants the child to wake it up on mm_release  ,英文不好,大概理解是  当子进程调用 mm_release 时,唤醒父进程。查看调用 CLONE_VFORK  的函数,发现都是vfork在使用。vfork 系统调用会要求先运行子进程,再运行父进程。所以猜测,是唤醒父进程使用的。

同时再搜索mm_release函数调用发现 vork_done 标志及注释,可以用来佐证上述猜想。

39行: 如果有人跟踪子进程,或者子进程设置里暂停状态,将子进程设置成暂停状态,设置TIF_SIGPENDING标志。(#define TIF_SIGPENDING 3 /* signal pending */ 不同系统这个值不一样)

47行: state用来记录进程状态。初始化成stop状态

48行:进程初始化是stop状态,如果再fork时没有设置stop状态,则将状态修改成 running。

50行:我理解是total_forks 是进程总数,新增加一个进程,就会+1, 销毁进程,应该是-1,但是没有看到-1操作。全局搜索,只看到显示函数有使用(应该是再/proc/stat下,或者是proc/pid/stat???)

52行:如果子进程被调试,则通知调试进程。

57行:VFORK要求先执行子进程,再执行父进程。

do_fork 函数读完,下一篇读 do_fork -> copy_process, 进程相关的信息都在这个函数里。

技术水平有限,虚心求教,欢迎指正。

do_fork(一)的更多相关文章

  1. Linux下进程的创建过程分析(_do_fork do_fork详解)--Linux进程的管理与调度(八)

    Unix标准的复制进程的系统调用时fork(即分叉),但是Linux,BSD等操作系统并不止实现这一个,确切的说linux实现了三个,fork,vfork,clone(确切说vfork创造出来的是轻量 ...

  2. swapper_pg_dir主内核页表、init和kthreadd、do_fork时新建子进程页表、vmalloc与kmalloc

    都是以前看到一个点扯出的很多东西,当时做的总结,有问题欢迎讨论,现在来源难寻,侵删! 1.Init_task.idle.init和kthreadd的区别和联系 idle进程其pid=0,其前身是系统创 ...

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

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

  4. vim + ctags + taglist配置和使用

    vim +ctags + taglist ,ctags+cscope 安装配置和使用 内容:VIM下ctags和taglist的安装配置方法:一键安装 ctags和cscope的方法 :vim语法高亮 ...

  5. Linux内核笔记--内存管理之用户态进程内存分配

    内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...

  6. linux内核分析作业6:分析Linux内核创建一个新进程的过程

    task_struct结构: struct task_struct {   volatile long state;进程状态  void *stack; 堆栈  pid_t pid; 进程标识符  u ...

  7. 《Linux内核设计与实现》读书笔记 第三章 进程管理

    第三章进程管理 进程是Unix操作系统抽象概念中最基本的一种.我们拥有操作系统就是为了运行用户程序,因此,进程管理就是所有操作系统的心脏所在. 3.1进程 概念: 进程:处于执行期的程序.但不仅局限于 ...

  8. linux内核分析作业5:分析system_call中断处理过程

    1.增加 Menu 内核命令行 调试系统调用. 步骤:删除menu git clone        (tab) make rootfs 这就是我们将 fork 函数写入 Menu 系统内核后的效果, ...

  9. Unix及类Unix系统文本编辑器的介绍

    概述 Vim是一个类似于Vi的著名的功能强大.高度可定制的文本编辑器,在Vi的基础上改进和增加了很多特性.VIM是纯粹的自由软件. Vim普遍被推崇为类Vi编辑器中最好的一个,事实上真正的劲敌来自Em ...

  10. TNS-12518 & Linux Error:32:Broken pipe

    最近一周,有一台ORACLE数据库服务器的监听服务在凌晨2点过几分的时间点突然崩溃,以前从没有出现过此类情况,但是最近一周出现了两次这种情况,检查时发现了如下一些信息: $ lsnrctl servi ...

随机推荐

  1. 2022-02-20:设计内存文件系统。 设计一个内存文件系统,模拟以下功能: ls: 以字符串的格式输入一个路径。如果它是一个文件的路径,那么函数返回一个列表,仅包含这个文件的名字。如果它是一个文件

    2022-02-20:设计内存文件系统. 设计一个内存文件系统,模拟以下功能: ls: 以字符串的格式输入一个路径.如果它是一个文件的路径,那么函数返回一个列表,仅包含这个文件的名字.如果它是一个文件 ...

  2. Alist云盘视频加密助手:支持云盘视频文件加密与在线播放,不用再担心视频文件被和谐了!

    在当前娱乐资源丰富的时代,人们每天都在接触各种视频资源.然而,网盘限速.版权审核.视频分级.少儿不宜等问题经常让人感到困扰.如何在保护隐私的前提下,让视频存储和分享变得更加便捷.安全呢?分享一款实用的 ...

  3. nodejs 入门基本概念

    nodejs 的诞生   Node.js 是2009的时候由大神 Ryan Dahl 开发的.Ryan 的本职工作是用 C++ 写服务器,后来他总结出一个经验,一个高性能服务器应该是满足"事 ...

  4. Random库用法详解

    梅森旋转算法实现 基本随机数函数 seed(a=None): 初始化给定的随机数种子,默认为当前系统时间. 只要随机数种子相同,产生的随机数序列也相同. random(): 生成一个[0.0,1.0] ...

  5. 计算机网络 ACL和ANT

    目录 一.ACL概况 二.ACL工作过程 三.ACL实验 四.ANT概况 五.ANT工作过程 六.ANT实验 一.ACL概况 概念:主要是对报文进行区分,路由器会对报文进行检查,查看是否符合通过标准或 ...

  6. 深入理解 apply()方法

    apply(thisArg) apply(thisArg, argsArray) thisArg 在 func 函数运行时使用的 this 值.请注意,this 可能不是该方法看到的实际值:如果这个函 ...

  7. 马拉车(manacher) & 回文自动机(PAM)

    补充,PAM 的 a[0]=-1,这一点我每次写都要忘记. 读了徐安矣2023年集训队论文写的,对于差分性质和习题,我会在理解清楚之后再补充.本篇博客仅讨论前两种算法. 首先,马拉车和回文自动机都是处 ...

  8. 关于Pod中进程在节点中的研究

    最近研究OpenShift virtulization, 各种Pod对KVM进程的封装,引发了Pod中进程到底在Node中是什么表现形势的好奇,因为对基础知识的不扎实,还是希望找个环境能仔细看看,建立 ...

  9. 深入探索C++对象模型(Inside the C++ object model) -- 摘阅笔记(关于对象 - esp 1)

    Object Lessons 关于对象 在C语言中,"数据"和"处理数据的操作(函数)"是分开声明的,也就是说 ,语言本身并没有支持"数据和函数&qu ...

  10. 创建springboot工程失败解决 spring initializr Error:cannot download

    创建springboot工程失败解决 问题描述 原因分析: 网络不好,因为springBooT项目的创建时必须联网的 解决方案: 方案一: 将创建 springBoot 工程的地址更换为如下的地址 阿 ...