这是通过三国演义串起操作系统的原理,之前写过五篇小马创业篇,这次改编为三国演义篇。
用一个创业故事串起操作系统原理(一)
用一个创业故事串起操作系统原理(二)
用一个创业故事串起操作系统原理(三)
用一个创业故事串起操作系统原理(四)
用一个创业故事串起操作系统原理(五)
第一回:
宴桃园豪杰三结义,开放平台启动内核
话说天下大势,分久必合,合久必分。IT江湖起起伏伏,风云变化。
19世纪80年代,AT&T开始经营长途电话业务,在20世纪30年代,一统有线通信市场,却终在2000年后跌落神坛。
20世纪30年代Motorola摩托罗拉诞生,第一台摩托罗拉牌汽车收音机问世,20世纪90年代登上无线通信宝座,却终在201X年痛失江山。
20世纪90年代,互联网行业开始崛起,先是网景,微软,雅虎,后是谷歌,Facebook,至今仍然风光无限。
在计算机领域内,也经历着同样的变化,孕育着一代又一代英雄,刘备就是其中的一员。
本来大一统的日子里面,刘备是没有机会的,在相当漫长的一段时间内,IBM作为大型计算机的巨无霸,从20世纪50年代,一直独领风骚到70年代,才遭遇到苹果公司在PC机上的小股骚扰。
终于在1980年,IBM开始稍微重视一下个人计算机市场,但由于可能还是不太重视的缘故(因为大型机照样能够让IBM赚很多很多钱),IBMPC的研发并没有让华生实验室来完成,而是单独成立一个团队,要求一年内研制成功IBMPC,然而时间紧,任务重,为了最快地研制出一台 PC ,这个只有十几人的小组不得不打破以前自己开发计算机全部软硬件的习惯,采用了英特尔公司 8088 芯片作为该电脑的处理器,使用MS-DOS作为其操作系统,从而缔造了日后的微软和英特尔两大帝国。1981年,第一款IBMPC问世,一经推出就抢掉了apple四分之三的市场。IBM仍然无敌。
但是1982年,事情发生了一些变化,IBM陷入美国司法部反垄断官司,IBM 必须公开一些技术,从而导致了后来无数 IBM-PC 兼容机公司的出现。
从而惠普,康柏,戴尔,联想等兼容机相继推出,从而进入了诸侯混战的阶段,这就是开放的X86时代。
这让刘备感到,机会来了。
刘备自幼熟读兵书,通晓历史,他知道,要想在这乱世立足,要有两样东西,一是人,也即兵,二是地,也即战场。
同理在开放的X86时代,兵也即执行命令的CPU,地也即兵驰骋的战场,也即CPU指令所操作的内存。
招募的兵(CPU)要有三方面的能力:
刘备知道,在乱世(X86平台),要会用兵,要会打仗抢地盘(要熟悉X86平台上CPU和内存的合作模式),虽然他现在还没有兵,但是这个场景他已经在梦中重复了N次了。
兵(CPU)是没有思想的,需要他去指挥才能作战。每次作战,他都应该先制定好作战计划(写好程序),作战计划既包括宏观的兵法,例如围魏救赵,欲擒故纵等(多进程,多线程协作模式),也包括微观的阵型,例如蛇形阵,八门金锁阵(一个个函数),当这些都准备好了,就可以交给部队去执行(创建进程)。同一个兵法和阵型,可以用在不同的战斗中,例如兵分两路,一路进攻A城市,一路进攻B城市,可以使用相同的兵法和阵型(一个程序可以创建多个进程)。
对于每次作战,战场(内存)都分为两部分,一部分为中军大营,发号施令的元帅在这部分(代码段),一部分是前方战场,拼杀发生在这部分(数据段)。士兵(CPU)通过不断的从中军大营(代码段)获取指令执行,指令一般包含两部分(CPU指令也包含两部分),第一部分是操作,例如攻击,防守,移动(CPU指令第一部分是操作,例如加法,减法,位移),第二部分是目标,例如战场上的某个高地,某个洼地(CPU指令第二部分是操作哪些数据)。
只要作战计划制定完善,士兵们执行得力,在战场上就无往而不胜。(CPU会通过指令指针寄存器不断的从代码段获取指令,交给运算单元执行,从内存读取数据到数据单元,用指令操作数据,将结果写回数据单元并最终写回内存,当所有的指令都执行完毕,进程就成功运行完毕了)。
刘备对这些战法了然于胸,但是还处于纸上谈兵的状态,属于通用的知识,真正干起来还需要结合实际情况,不过一旦有了这个创业思想,便是创业的开端了(通用的知识就像BIOS,对于任何一个系统来讲都是一样的,不像将来计算机启动之后的操作系统,可以根据用户的输入进行相应的处理,但是BIOS的启动是整个系统启动的第一步)。
带着这个思想,刘备虽孑身一人,便开始四处寻找创业伙伴。终于在招兵告示那里,遇到了关羽和张飞。
兄弟三人一见如故,相谈甚欢,刘备说:我自幼熟读兵书,创业想法已久,但是一没钱,二没人。
张飞说:“吾颇有资财,当招募乡勇,与公同举大事,如何。”于是三人桃园结义,祭罢天地,复宰牛设酒,聚乡中勇士,得三百余人。这家创业公司就这样成立了。
这就像系统启动初始,只有有1M的内存空间。在1M空间最上面的0xF0000到0xFFFFF这64K映射给ROM,通过读这部分地址,可以访问这个BIOS里面的指令。
BIOS要检查一些系统的硬件是不是都好着呢,然后建立基本的中断向量表和中断服务程序,至少要能够使用键盘和鼠标。
接下来,刘备就要带着关羽和张飞以及这仅有的三百人,开始闯荡江湖了。(接下来,BIOS就要开始寻找和加载内核,启动系统了)
第二回:战吕布陶谦让徐州,保护模式空间更大
刘备首先建立的功业是帮助平定黄巾起义,从而被封为安喜县县尉,也即县公安局长,这是刘备事业起步的第一跃。(在启动盘的第一个扇区,512K的大小,我们通常称为MBR,Master Boot Record,主引导记录/扇区。这里保存了boot.img,BIOS手册会将他加载到内存中的0x7c00来运行)
在安喜县,刘备并没有实现自己的抱负,反而受督邮欺压,从而鞭打督邮后投奔公孙瓒,因军功封为平原县县令,事业再上升一步。(
boot.img做不了太多的事情。他能做的最重要的一个事情,就是加载grub2的另一个镜像core.img。core.img由lzma_decompress.img、diskboot.img、kernel.img和一系列的模块组成,boot.img将控制权交给diskboot.img后,diskboot.img的任务就是将core.img的其他部分加载进来,先是解压缩程序lzma_decompress.img,再往下是kernel.img,最后是各个模块module对应的映像。
)
这个阶段,刘备依旧是小打小闹,但是很快,情况就有了改观。(从diskboot.img到lzma_decompress.img,系统一直处于实模式,在1M的内存空间里面打转,但是从lzma_decompress.img开始,他会调用real_to_prot,切换到保护模式,这样就能在更大的寻址空间里面)
关羽先是温酒斩华雄,后来三兄弟更是三英战吕布,这下在诸侯里面算是打出了名声。
刘备得知陶谦有难,从公孙瓒处借得两千人马与勇将赵云,会同本部三千人,随北海太守孔融一起去救徐州。陶谦为保徐州,见刘备乃汉室宗亲,才德兼备,欲将徐州让与刘备。经三辞三让,最终刘备答应权领徐州,终于得到了创业路上的第一块大的军事重镇,从此摆脱了小打小闹。(系统进入保护模式后,可访问的内存空间增大,对于32位系统可达4G,对于64位系统可达
256TB的空间
)
在徐州,刘备还得到了几个内部管理的文臣人才,孙乾口才好,擅长外交,
糜竺曾经大力资助刘备,并将妹妹许配给刘备,就是糜夫人,你不要小看糜竺,以为此人在三国演义上低位不高,在历史上,取西川后,糜竺爵位在诸葛亮之上,深得刘备器重。
从此刘备有文有武,就像他对水镜先生说的一样,“备虽不才,文有孙乾、糜竺、简雍之辈,武有关、张、赵云之流,竭忠辅相,颇赖其力。”,从而有了内外的分别,整个班子才算完整。(系统进入保护模式后,开始区分内核态和用户态,用户态不能随便访问内核态,需要通过系统调用)
在徐州的三辞三让,使得刘备进一步确认了自己的创业公司的文化内核——仁义。这个内核是刘备将来成功的根基,就像他自己说的,“今与吾水火相敌者,曹操也。操以急,吾以宽;操以暴,吾以仁;操以谲,吾以忠:每与操相反,事乃可成。若以小利而失信义于天下,吾不忍也。”,从而也奠定了他的失败根源。(
kernel.img里面的grub_main会给展示操作系统的列表,让用户进行选择。无论是枭雄的内核,还是仁义的内核,就在这一刻选定了,以后不会再变了
)
第三回:
领徐州刘备初创业,启内核模块初始化
占据徐州之后,刘备有了自己的领地,可以开始规划作为一个创业公司的“主公”应该做哪些事情了。(内核的启动)
首先,天下还不太平,不免要打仗,仗怎么打,如果保障作战过程中部队的有序管理,要有一个作战管理体系。
由于前期打仗的时候,都是刘备亲自上的,由于关羽张飞尚无经验,所以刘备制定第一个作战管理的模板(
0号进程
),但是是虚拟的,不对应一个真实的战斗(操作系统的
0号进程
init_task
是进程列表的第一个,不对应任何一个运行中的进程)。
如果是大一些的战役,可能由多次战斗组成,还需要刘备居中协调,所以一个作战调度系统也是需要的。(sched_init进程调度初始化)
兵马未动粮草先行,为了让前方的将士可以很好的请求后方的资源,需要有一个作战请求响应体系,只要关羽张飞给后方发一个信号,后方的糜竺,孙乾就可以开始拨发粮草。(操作系统trap_init
设置了很多中断门Interrupt Gate,用于处理各种中断,以便快速响应突发事件;还可以提供系统调用,方便进程请求内核资源。
)
终于有了徐州城,这个唯一的地盘要好好的规划管理起来。(mm_init用于初始化内存管理系统)
这一切都规划完毕,接下来兄弟们就要干起来,外部的事情就交给关羽张飞,内部的事情就交给糜竺,孙乾。(内核初始化最后调用rest_init,里面
第一件事情是调用kernel_init运行1号进程。这个1号进程会在用户态运行init进程。这是第一个以用户态运行的进程,之所以叫init,就是做初始化的工作,他是将来所有用户态进程的祖先进程。
第二件事情是调用kthreadd运行2号进程。这个2号项目是内核进程的祖先。将来所有的进程都有父进程、祖先进程,会形成一棵进程树。
)
第四回:
攻袁术中计失徐州,建立进程管理体系
占据徐州以后,刘备接到的第一个作战任务是攻打袁术,其实是曹操的
驱虎吞狼之计。
糜竺曰:“此又是曹操之计。”玄德曰:“虽是计,王命不可违也。”遂点军马,克日起程,孙乾曰:“可先定守城之人。”玄德曰:“二弟之中,谁人可守?”关公曰:“弟愿守此城。”玄德曰:“吾早晚欲与尔议事,岂可相离?”张飞曰:“小弟愿守此城。”玄德曰:“你守不得此城:你一者酒后刚强,鞭挞士卒;二者作事轻易,不从人谏。吾不放心。”张飞曰:“弟自今以后,不饮酒,不打军士,诸般听人劝谏便了。”
刘备托付完张飞,便和关羽一起商议攻打袁术的作战计划。由于两人都是读过兵书的,所以比较容易达成一致,但是必须要变成士兵们比较容易理解的指令,于是二人对着阵图敲定细节后,方才出发。(
C/C++语言都是接近人类的语言,CPU无法执行,需要通过编译,转换为CPU可以听懂的二进制语言。编译好的文件有固定的格式,ELF格式。代码的执行从父进程fork一个子进程,然后在子进程中,调用exec系统调用, 然后到了内核里面,通过load_elf_binary将ELF二进制执行文件加载到子进程内存中,交给CPU执行。
)
虽然前方作战还算顺利,然后后方出了篓子。张飞在戒酒宴上,劝吕布岳父曹豹饮酒,曹豹不饮,被张飞鞭打。曹豹连夜差人送信与吕布,约布袭取徐州。张飞因醉后不能力战,只得抛下刘备家眷,出东门而去。徐州为吕布所有,刘备无奈,只好向吕布求和,暂屯小沛。
这次失败,让刘备意识到,前面都是小打小闹,可以通过兄弟情义治军,如果将来治理大的地盘,还是需要军法严明,靠制度而非人治。(应该建立进程管理系统)
所有进程都放在一个task_struct列表中,对于每一个进程,都非常详细地登记了他方方面面的信息。
每一个进程都应该有一个ID,作为这个进程的唯一标识。到时候调度啊、发送信号啊等等,都按ID来,就不会产生歧义。
进程应该有运行中的状态,TASK_RUNNING并不是说进程正在运行,而是表示进程在时刻准备运行的状态。这个时候,要看CPU有没有空,有空就运行他,没空就得等着。
有时候,进程运行到一半,需要等待某个条件才能运行下去,这个时候只能睡眠。睡眠状态有两种。一种是TASK_INTERRUPTIBLE,可中断的睡眠状态。这是一种浅睡眠的状态,也就是说,虽然在睡眠,等条件成熟,进程可以被唤醒。
另一种睡眠是TASK_UNINTERRUPTIBLE,不可中断的睡眠状态。这是一种深度睡眠状态,不可被唤醒,只能死等条件满足。有了一种新的进程睡眠状态,TASK_KILLABLE,可以终止的新睡眠状态。进程处于这种状态中,他的运行原理类似TASK_UNINTERRUPTIBLE,只不过可以响应致命信号,也即虽然在深度睡眠,但是可以被干掉。
一旦一个进程要结束,先进入的是EXIT_ZOMBIE状态,但是这个时候他的父进程还没有使用wait()等系统调用来获知他的终止信息,此时进程就成了僵尸进程。
EXIT_DEAD是进程的最终状态。
另外,进程运行的统计信息也非常重要。例如,有的CPU很长时间都在执行一个进程,这个时候你就需要特别关注一下;再如,有的时候进程切换过于频繁,这会大大影响他的工作效率。
在进程的运行过程中,会有一些统计量,例如进程在用户态和内核态消耗的时间、上下文切换的次数等等。
进程之间的亲缘关系也需要维护,任何一个进程都有父进程。所以,整个进程其实就是一棵进程树。而拥有同一父进程的所有进程都具有兄弟关系。
另外,对于进程来讲,权限的控制也很重要。例如,我这个进程能否访问某个文件,能否访问其他的进程,以及我这个进程能否被其他进程访问等等
另外,进程运行过程中占用的资源,例如内存、文件系统也需要在进程管理系统里面登记。
刘备下令,以后所有的作战任务都要按军法来,才能保证战斗的胜利。
但是此次失败,让刘备丢了来之不易的徐州。后来虽然白门楼计除了吕布,但是生活在曹操和袁绍的夹缝之中,先投奔曹操被煮酒论英雄吓了个半死,后来投奔袁绍兄弟三人分离,险些被杀害,直到关羽千里走单骑,兄弟三人古城相会,事业又重新回到了起点。
经此一劫,刘备也深深感到,自己虽然熟读兵书,但是在兵法方面还是欠缺,需要觅得贤士相助,才能成就大业。
第五回:
觅贤才玄德得徐庶,多进程调度有秘方
在荆州,经过司马徽指点,刘备决定去寻找一个可以运筹帷幄的人才。
水镜问曰:“吾久闻明公大名,何故至今犹落魄不偶耶?”玄德曰:“命途多蹇,所以至此。”水镜曰:“不然。盖因将军左右不得其人耳。”玄德曰:“备虽不才,文有孙乾、糜竺、简雍之辈,武有关、张、赵云之流,竭忠辅相,颇赖其力。”水镜曰:“关、张、赵云,皆万人敌,惜无善用之之人。若孙乾、糜竺辈,乃白面书生,非经纶济世之才也。”玄德急问曰:“奇才安在?果系何人?”水镜曰:“伏龙、凤雏,两人得一,可安天下。”
刘备得到的第一个人才,既不是卧龙,也非凤雏,而是徐庶,这是刘备的第一个军师,从此刘备才有了复杂的战场运筹调度机制。
徐庶辅佐刘备,初次用兵,连败曹操,使赵云一举破了八门金锁阵,关羽也取了樊城。并破解了曹仁的劫寨。
却说单福正与玄德在寨中议事,忽信风骤起。福曰:“今夜曹仁必来劫寨。”玄德曰:“何以敌之?”福笑曰:“吾已预算定了。”遂密密分拨已毕。至二更,曹仁兵将近寨,只见寨中四围火起,烧着寨栅。曹仁知有准备,急令退军。赵云掩杀将来。仁不及收兵回寨,急望北河而走。将到河边,才欲寻船渡河,岸上一彪军杀到:为首大将,乃张飞也。曹仁死战,李典保护曹仁下船渡河。曹军大半淹死水中。曹仁渡过河面,上岸奔至樊城,令人叫门。只见城上一声鼓响,一将引军而出,大喝曰:“吾已取樊城多时矣!”众惊视之,乃关云长也。仁大惊,拨马便走。云长追杀过来。曹仁又折了好些军马,星夜投许昌。于路打听,方知有单福为军师,设谋定计。
在遇到徐庶之前,刘备的战场调度都是单线的,和谁打,如何打之类的。有了徐庶,战场调度就变成了多线配合的,将一场战役分为多个战斗,多个将领配合完成,互相接应。
在Linux里面,无论是进程,还是线程,到了内核里面,我们统一都叫任务,由一个统一的结构task_struct进行管理。
对于操作系统来讲,他面对的CPU的数量是有限的,干活儿都是他们,但是进程数目远远超过CPU的数目,因而就需要进行进程的调度,有效地分配CPU的时间,既要保证进程的最快响应,也要保证进程之间的公平。
如何调度呢?一种方式就是排队。
一个CPU上有一个队列,队列里面是一系列sched_entity,每个sched_entity都属于一个task_struct,代表进程或者线程。
调度要解决的第一个问题是,每一个CPU每过一段时间,都要想一下,CPU的队列里面有这么多的进程或者线程,应该取出哪一个来执行?
这就是调度规则或者调度算法的问题。