NEW PROCESS
火影忍者想必大家都很熟悉吧,就算没看过也应该都听说过,里面有着各种各样的忍术,加上不同的结印手势,那真是相当的炫酷啊。可这和计算机有什么关系呢?今天我们就要使用两种忍术来创建一个新进程。
没错,就是要用两种忍术来创建一个新进程,分别是分身术 fork,和变身术 exec。前文说过 init 第一个进程的创建,因为是第一个进程,所以必须得“自己手动”的建立进程初始数据。而后续的进程就不用这么麻烦啦,直接一个分身,一个变身就能创建一个新进程。
这两个忍术可得好好领悟认真学,鸣人可是靠着这两种忍术打遍天下无敌手,就算是在最后的BOSS战(面试)里面都起到了重要作用。下面我们就来具体学学这两种术法。
准确的说应该是影分身,火影里面普通的分身术和影分身的区别知道吧,不知道感兴趣的可以去看看火影,咱这就不解释了,不然变成火影的公众号了。
不过咱们还是要来百科百科影分身,官方解释为:使用查克拉造出有实体的分身,具有独立于本体的意识和一定的抗打击能力,可应用于各种忍术之上,正常解除后分身的记忆和经验会回归本体。
而我们的新进程呢,是使用一定物理空间来创建自己的PCB,页表等结构,它是独立于父进程存在的一个进程,能够被调度上CPU,可运行各种新程序,运行完后退出再由父进程回收。这个过程简直完美契合影分身之术有没有,简直怀疑岸本齐史是不是另有一个计算机兼职。
下面我们来具体看看影分身fork这个秘籍,但是呢 fork 大家都应该都很熟悉了,就不再做过多的铺垫介绍,简单来说就是根据父进程克隆出一个几乎一模一样的子进程出来。在这儿也不举 fork 那个 if-else 判断 pid 的经典的却老掉牙的例子了,咱们来谈点不一样的。
首先来看看影分身简化版的残卷秘籍(这种方式对于计算机来说是低效的)
上述的 fork 只是残卷,主要是想说明 fork 的一种实现过程思路。虽然这种方式在忍术中被列为B级,但是在计算机的世界里,将父进程的资源全部拷贝一份的实现方式是非常低效的,后面我们会讲另一种高效的方式:写时复制。现在先来看看下面几个通用的问题:
这是CSAPP里面的原话,个人认为单独说这么一句总结性的话语是有歧义的,对于初次接触到fork的朋友来说可能很迷惑。一个函数只能有一次返回,是不可能返回两次的。即使我们平时写程序时可能会使用多个 return 语句,但最终肯定只会从一个 return 中返回。那fork函数作何解释呢?
fork 之后一个进程就变成了两个进程,两个进程两个fork 两个返回,而不是说一个 fork 函数就返回两次
fork 函数有三种返回值:
子进程是克隆出来的,返回值怎么还不一样?看清前面说的,根据父进程克隆出几乎一模一样的子进程来,说明并不是完全相同。
那返回值是怎么回事呢?在Linux里面系统调用采用中断门实现,所以调用 fork 时会触发中断,中断就会保存上下文,其中包括了eax寄存器的值。
据调用约定,eax 寄存器里面存放的是返回值,所以据上面的残卷可以看出,fork 时会修改子进程中断上下文里的 eax 为0。如此父进程中的 fork 和子进程中的 fork 便会返回不一样的值。
而返回 -1,多数情况是进程数达到上限或者内存不足,这种情况下根本就没有创建新的进程,也谈不上两次返回和返回不同的值。
这似乎是废话,但是为什么呢?我看到CSDN上有篇博客是这样回答的,大概意思是 fork 函数只是将后面要执行的代码拷贝到新的进程,这篇博客的访问点赞评论都很高。但是私以为这种说法是不对的,至少在我看的一些系统 fork 源码中没有这么实现的。
那为什么 fork 之后父进程子进程都是是接着 fork 后面的代码运行呢?其实很简单,就是中断上下文的保存于恢复。前面说过 fork 系统调用通过中断实现,中断时父进程保存了当前执行流的位置即 cs:eip 的值,然后 fork 函数复制了一份给子进程,所以父进程子进程中断返回时都会继续执行fork后面的代码。
因此fork前是一个进程在执行,fork 后是两个进程在执行同一块儿代码(如果没调用 exec 变身的话)
最后来看低效版的 fork 动态图,实实在在的将父进程的资源复制了一份。
前面我们的分身术 fork 函数只能克隆出来一个与父进程几乎相同的子进程,它们执行的是同一个程序,但经常我们需要的是一个全新的进程,它能运行其他程序。这就需要变身,用到 exec 函数。exec 函数总共有6个,其中execve是内核的系统调用,其他5个execl, execv, execle, execlp, execvp都是在execve之上实现的。
execve函数原型如下:
我们要加载的文件叫做可执行目标文件,Linux里面可执行目标文件的格式为ELF,而Windows里面是PE,注意不是 exe,exe 只是后缀名。
ELF格式简介
ELF 指的是 Executable and Linkable Format,可执行可链接格式。从命名中也可以看出它有两种视图:执行和链接两种视图。
上面这图大家应该都很熟悉了吧,后面两种目标文件,可重定位目标文件和可执行目标文件就分别对应着ELF格式文件的链接视图和执行视图。
细究ELF文件的话,内容还是很多的,我们在这儿捡重点,exec用的上的说:
先来从总体上看看两种视图的结构:
链接视图以节为单位,执行视图以段为单位。这里的段和我们所说的内存分段的段的含义是不同的,要区分开。
实际的ELF文件里面的节和段很多,这里只是列出了比较重要需要了解的一部分,下面简要说明一下:
各元素表示的意思大都已经说明,根据命名应该还是很好记住各元素所代表的意义,下面再重点说几点:
同上简单解释几点:
1、程序段的类型有很多,我们只需要了解可装载段,顾名思义,需要装载到内存里面的段,比如代码段,数据段。
2、这里涉及了多种段,程序段类型里面的段,数据段代码段等里面的段,还有内存的分段,都是段不要混淆了。
3、一般说来 p_filesz <= p_memsz,这是因为bss节的存在,它并不存在与文件中,仅存在与运行时的内存当中。这是因为 bss 节中存放的是未初始化的全局变量,它们的值是无意义的,如果我们在文件中分配空间将这些变量的值存储下来也就无意义。所以我们的目标文件中其实并不需要 bss 的实体,只需要记录bss 的大小位置等相关信息即可。
4、虽然在文件中存储变量没有意义,但是人家好歹也是未初始化的全局变量,需要在内存中专门为它们开辟空间存储它们。
从上面的 ELF Header 和 Program Header 中可以看出程序各段的大小位置都已经确定好了了,我们只需要将它们加载到相应位置即可,来看看 exec 变身术的残卷秘籍:
同 fork 那本秘籍,主要是想展现 exec 实现的一个大致过程思路,每个步骤写的应该还是比较清晰,照例下面说几点重点:
装载映射的段都是可装载段,具体的装载过程可以用读取文件 read 和 lseek 系统调用来实现。
read 的作用就是读取文件到内存的一个缓冲区,而 read,lseek 两函数需要的参数在程序头中都有记录,所以理论上来讲实现起来应该是很容易的。
exec 需要修改原进程内核栈中的一些信息,最主要的就是将中断上下文里面的 eip 改为 ELF 文件中的入口地址。
ELF头中的 p_entry 入口地址是什么?是main函数的地址吗?非也。那是什么呢?这要牵扯一个概念,运行库,运行库涉及的知识很多,在这就长话短说,讲讲与本文有关的。
简单说来,运行库就是标准库的扩展,会在 main 函数运行之前准备好环境,运行完之后再进行收尾的工作。
本文就只说说准备运行环境的部分,这部分可以看做是一个函数,全局符号为_start,也就是函数名为_start。_start才是我们运行的第一个函数,ELF 头中的入口地址 p_entry 就是它。
_start 函数的工作之一就是压入 main 函数的参数。
前面我们的伪码中是把实际的命令行参数传到了用户态的线性空间中,但是要清楚 main 函数的参数可不是实际的命令行参数,而是命令行参数的个数和字符串指针数组的地址。这两个参数压栈操作就在_start 中进行。毕竟 main 函数也是一个被调用的函数,在调用之前需要传参。
exec函数如果发生错误会返回-1,正确则不返回。
exec 函数里面还调用了许多其他函数,这些函数出错,exec 没能继续运行下去的话是会直接返回-1的,只是上面伪码没体现出来。
要知道 exec 这个函数就像是推到原进程然后重来,改变了很多信息,中断的执行上下文被大幅度改变,调用 exec 的代码也是不复存在的。从这个角度看exec从未成功返回,取而代之的是执行的新程序被映射大进程的地址空间。
以上来自深入理解 Linux 内核的解释,感觉听抽象模糊?也可以尝试这样理解,来自于操作系统真相还原的一个系统设计。
在这个OS设计里,exec 如果成功运行到最后,直接使用 jmp 语句跳到中断退出点。jmp 语句不像 call,它是有去无回的,所以没有不会再返回到 exec 函数里,而是直接弹出中断上下文的 eip 入口地址去运行新程序了。
再来看看exec的动态图,想要表达的意思很简单,就是在原进程上推到重来:
好了,关于分身术和变身术咱们就传授到这,下面我们要来学以致用,推陈出新,创造一门新忍术。
前面说过,影分身之术虽然等级很高但是有弊端的,特别是在施展多重影分身之术时可能会因为查克拉消耗太过剧烈而伤及自身,所以被列为禁术。而同样的,咱们最初版的 fork 因为复制了父进程的全部资源而浪费了太多时间空间,也不再使用。
现在的 fork 都是用了写时复制技术,这项技术可了不得,面试中经常提到。岸本齐史肯定不会这个,不然的话肯定再创一门 S级忍术,没有实体的假分身可以变成真的,真的可以变成假的。真真假假,虚虚实实,补不足而损有余,这样就可以减少不必要的查克拉消耗,还能达到兵者诡道也的效果。
扯远了扯远了,写时复制这项技术可没有那么强大,但也有类似的机制和目的,减少空间时间消耗,高效的完成进程创建任务,来具体看看:
前面我们的fork是傻瓜性的,真的将父进程的所有资源全部复制了一份,但实际上是不必要的。
如果我们不调用 exec 运行新程序,那么实际上父子俩进程很多的资源是可以共用的,比如代码部分。
而如果调用 exec 来执行新程序,exec 要删除掉已存在的用户区域,复制父进程的资源也无意义。所以这样的fork有很大弊端,不适用。
顾名思义的简单解释就是,fork 时不会真的分配新的物理页复制资源,子进程直接引用共享父进程的物理空间。只有一个进程要写数据,改变共享内容时,才单独复制一份出来。
这样就避免了不必要的资源复制。在面试中肯定不能只回答这么一点内容,那是过不了关的,咱们还需细剖注意几个问题,就直接已干货的形式罗列出来了,如下所示。
1、**即使利用写时复制技术,fork时也还是为子进程创建一些单独的资源,比如PCB,页表。也就是说要为其分配新的物理空间来存储这些资源,这些东西是不会在物理上共享的。**
2、**父子进程各自拥有一套页表,子进程的页表从父进程哪儿复制过来的,内容是相同,所以父子进程映射到了同一个物理空间。但因为是两套页表,所以父子进程的虚拟地址空间是不同的,只是说两个虚拟地址空间对应的是同一个物理空间。或者按照CSAPP里面的话来说,相同但独立的地址空间。**表述的可能不太一样,但实际表达的意思是一样的,能清楚明白是指就好。
3、写时复制的实现原理:
如果父子进程都是读取相同的物理页,那么父子之间是相安无事的。但是只要有一个写就会起冲突,内核就会把这个页的内容拷贝到一个新分配的物理页,并更新写进程的页表项使其指向新分配的这个物理页。最后再回复页面的可写属性。
再来看看动图直观感受一下:
所以啊,fork之后,你以为现在是父子两个进程实体,但实际上内存里面只有父进程一个完整的实体。你又以为子进程在内存里面没多少自己单独的资源时,过了一会儿,说不定又因为写操作给分配了。
所以吧,真不是我生搬硬套,这虚虚实实的感觉与我那创造的S级忍术还是有些相似的对吧。到现在这个S级术法还没取名字呢,为了纪念写时复制技术,而且这个术法这么厉害,干脆就叫做牛影分身吧。(为啥叫这名儿能懂吧,没看明白的看看写时复制的英文简写?)
最后这一部分简单谈谈上述三个函数的区别,同样的不多说直接以干货的形式罗列出来:
关于这部分就先说这么多吧,了解了解即可,最常用的还是fork函数。
本文主要介绍了火影里面的分身术和变身术,还自创了一门忍术牛影分身。哦不,是两个函数fork和exec,还有写时复制技术。
本文给出了简化版的秘籍,还是残卷,诸位不要真的去修炼,怕走火入魔。这只是用来给出一种实现的思路,体现运行过程,相当于流程图。诸君看看了解过程就好,不要太过较真。
这也不是为自己的不严谨开脱,而是内核这个东西吧,内容太多也太复杂,想要通俗易懂的表达出来,着实不容易,这是客观的事实。当然与本人的能力水平也有关,诸位还请见谅,如果哪儿有错还请批评指正。
最后在谈谈鸣人吧,漩涡鸣人一直是我比较喜欢的角色,天资并不聪颖的他始终保持着积极乐观的态度,经过坚持不懈的努力终于实现了自己的梦想成为了一代火影。
在这儿也祝愿大家能像鸣人一样始终保持着积极乐观的心态,早日实现自己的人生梦想!!!
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/QAlt8uEauVe3mLcHEDmw-Q
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。