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. ICML 2017-Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks

    Key Gradient Descent+TRPO+policy Gradient 训练模型的初始参数,模型在新任务上只需参数通过一个或多个用新任务的少量数据计算的梯度步骤更新后,就可以最大的性能.而 ...

  2. docker部署gitlab CI/CD (二)终篇:部署gitlab runner和添加gitlab-ci.yml文件 终极踩坑版

    关于gitlab部署的教程还好,有的看,但到了cicd环节,简直痛苦面具,教程虽多,但断断续续,先不说大部分都是只截取片段,让人云里雾里,不会的看不懂,懂的不需要看,根据步骤跑不起来不说,改了一堆,完 ...

  3. odoo开发教程五:高级视图

    树视图 tree视图表现出来是列表视图,列表中一行一纪录.可以根据每行纪录的某字段值不同而把每行以不同样式显示. decoration-{样式}="条件" 样式主要有: bf(fo ...

  4. 「高频面试题」Redis的持久化方式有哪些?

    RDB RDB(Redis DataBase)持久化是把当前Redis中全部数据生成快照保存在硬盘上.RDB持久化可以手动触发,也可以自动触发.save和bgsave命令都可以手动触发RDB持久化.除 ...

  5. 曲线艺术编程 coding curves 第四章 利萨茹曲线(Lissajous Curves)

    第四章 利萨茹曲线(Lissajous Curves) 原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池 ...

  6. 【Python】如何在FastAPI中使用UUID标记日志,以跟踪一个请求的完整生命周期

    为什么要使用uuid标记日志? 在分布式系统中,一个请求可能会经过多个服务,每个服务都会生成自己的日志.如果我们只使用普通的日志记录,那么很难将这些日志串联在一起,以至难以跟踪一个请求的完整生命周期. ...

  7. 【后端面经-Java】AQS详解

    目录 1. AQS是什么? 2. AQS核心思想 2.1 基本框架 2.1.1 资源state 2.1.2 CLH双向队列 2.2 AQS模板 3. 源码分析 3.1 acquire(int) 3.1 ...

  8. SQL Sever 基础语法(增)

    SQL Sever  插入(Insert)基础语法详解 在SQL中,向表中插入数据是最基础的,任何对数据处理的基础就是数据库有数据,对于SQL而言,向表中插入数据有多种方法,本文列举3种: (一) 标 ...

  9. Kubernetes(k8s)控制器(五):有状态应用StatefulSet

    目录 一.系统环境 二.前言 三.StatefulSet简介 四.有状态应用和无状态应用区别 五.StatefulSet 5.1 创建StatefulSet 5.2 scale扩展副本数 5.3 创建 ...

  10. AR增强现实 之Metaio For Unity 开发 之HelloWorld

    开发工具 unity 4.6     MetaioSDK 6.1       代码编辑器 VS 2013 上图不会配置的请自行百度 1.创建项目并且导入Metaio SDk 开发包 2.导入后目录图 ...