18 | 进程的创建:如何发起一个新项目?
刘超
该思维导图由 AI 生成,仅供参考
前面我们学习了如何使用 fork 创建进程,也学习了进程管理和调度的相关数据结构。这一节,我们就来看一看,创建进程这个动作在内核里都做了什么事情。
fork 是一个系统调用,根据咱们讲过的系统调用的流程,流程的最后会在 sys_call_table 中找到相应的系统调用 sys_fork。
sys_fork 是如何定义的呢?根据 SYSCALL_DEFINE0 这个宏的定义,下面这段代码就定义了 sys_fork。
sys_fork 会调用 _do_fork。
fork 的第一件大事:复制结构
_do_fork 里面做的第一件大事就是 copy_process,咱们前面讲过这个思想。如果所有数据结构都从头创建一份太麻烦了,还不如使用惯用“伎俩”,Ctrl C + Ctrl V。
这里我们再把 task_struct 的结构图拿出来,对比着看如何一个个复制。
dup_task_struct 主要做了下面几件事情:
调用 alloc_task_struct_node 分配一个 task_struct 结构;
调用 alloc_thread_stack_node 来创建内核栈,这里面调用 __vmalloc_node_range 分配一个连续的 THREAD_SIZE 的内存空间,赋值给 task_struct 的 void *stack 成员变量;
调用 arch_dup_task_struct(struct task_struct *dst, struct task_struct *src),将 task_struct 进行复制,其实就是调用 memcpy;
调用 setup_thread_stack 设置 thread_info。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
在内核中创建进程是一个复杂的操作,本文详细介绍了这一过程。通过系统调用fork来发起一个新的进程,然后在内核中执行sys_fork系统调用,最终调用_do_fork函数来完成进程的创建。_do_fork函数首先复制task_struct结构,然后处理权限、调度、文件和文件系统、信号以及进程内存空间等相关变量。文章详细介绍了每个步骤的具体实现细节,包括复制task_struct结构、处理权限、初始化统计量、设置调度相关变量、复制文件和文件系统信息、初始化信号相关变量、复制进程内存空间等。整个过程展现了在内核中创建进程所涉及的复杂操作和技术细节。读者可以通过本文了解到在内核中创建进程的具体步骤和技术细节,为深入理解内核操作提供了重要参考。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《趣谈 Linux 操作系统》,新⼈⾸单¥68
《趣谈 Linux 操作系统》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(37)
- 最新
- 精选
- 刘強文章中出现了SYSCALL_DEFINE0宏定义,不明白,就网上查了一下,一看吓一跳,宏定义里面又有一堆宏定义,其实就是一个函数调用,为什么弄得这么复杂呢?原来是为了修复一个bug。这让我意识到linux内核代码的复杂性。linux是一个集大成者,为了适应各种硬件架构平台,修复各种意想不到的bug,里面充斥着各种兼容性代码,修复补丁等等。而且里面的代码也是世界各路大神,黑客写出来的,为了保证内核的安全性,健壮性,扩展性,考虑的东西非常之多,充斥着各种奇技淫巧,不是我等普通人短时间能够理解。每一行代码,甚至一个宏定义,都是要花时间研究的。从这个角度上来说,linux就像是一个迷宫,如果没有一个向导,进去后估计就出不来了。也许这个专栏的作用就是充当一个向导,欣赏沿途风景的同时,带领我们穿越迷宫,找到出口...
作者回复: 是的。
2019-05-0844 - 刘強有个问题: 在数据库中,有个事务的概念,也就是保证一连串操作的原子性,如果其中任何一步错误,整个操作回滚,回到原来的状态,好像什么也没发生。但是在文章中我看到,在创建进程的过程中,步骤太多了。每一步都要申请空间,复制数据。如果其中一步发生了错误,怎么保证释放这些空间,回到原来状态?
作者回复: 错了会做错误处理的,没有啥捷径,都是代码里面自己做的,写c就要这样,每一步都要清楚自己创建了什么,万一错误应该销毁什么。如果程序员不做这个,没有人帮忙,不像java还有个gc
2019-05-08320 - Milittle老师,要是能把对应代码路径给出就好了,有时候自己找不见,谢谢老师~
作者回复: 其实不用纠结,因为代码过一阵就变了,关键是理解原理和流程。我原来做过代码逐行分析的这种,但是发现这种文章过一阵就没法看了。
2019-05-10217 - zhengfan刘老师: 遇到一个问题。 您在上面两个章节提到过“进程调度第一定律”,是说任何被调度的task(无论是获得还是交出运行权一方)都是在调用__schedule方法,并因此在进程实际切换完成后不需修改指令指针寄存器。 以此来思考本节介绍的创建进程过程。父进程在交出运行权的时候没什么特殊的,一定是在执行__schedule方法。 然而当子进程获得运行权的时候,因为之前它没运行过,不是通过__schedule方法交出运行权的,当前的指令指针寄存器和子进程运行状态的上下文(dup_task_struct中?)不相符吧?这样不会出问题吗?
作者回复: 不会的,调度这个函数是在内核里面的,这个逻辑其实不属于任何一个进程,反而是上下文的数据才标志了属于哪个进程。而且子进程刚fork完之后,没有exec之前,所有都和父进程一模一样
2020-04-178 - 注意力$超哥,Oracle 这种多进程的数据库,和mysql 这种单进程多线程的数据库,在进程管理上有什么优势呢?看见创建进程这么复杂,资源消耗也多
作者回复: 创建复杂,创建起来就好了,很多多进程的软件,也不是任务来了,现创建进程的,而是事先创建好了,等待分配任务。
2020-05-306 - 尚墨反复研读都已经高亮了。我几乎每篇都要听,读三次以上,才能懵懵懂懂。
作者回复: 再难的知识就怕反复研究,加油
2019-05-115 - 一苇渡江老师写的太棒了,特别是这个图,肯定是花了不少时间,把这个图手抄了一遍,时不时拿出来看看
作者回复: 手抄啊,牛
2019-05-085 - 蚂蚁内推+v内核态的内核进程和用户态的用户进程创建过程有区别吗?
作者回复: 有区别的
2019-05-2432 - 安排调度类是全局的吗?还是每个cpu核有自己的调度类集合?
作者回复: 类是全局的。里面主要实现的是算法。
2019-05-0821 - 周平讲得好的细节,与前面的内容可以无缝连接,不至于管中窥豹,让学习者越学越乱,谢谢老师
作者回复: 赞
2019-05-17
收起评论