linux源代码分析
发表于2017-08-28 11:40 | 次阅读 | 0条评论 | 作者:siru90
linux现在的代码以经有600多万行了,驱动部分是个大头,占了近60%左右。有些人说驱动不应该算入核心的,但我觉得,驱动应该算是内核中非常重要 的部分,再加上它的确是运行在内核空间的,所以我也把它归入内核部分。本文不会涉及linux的用户空间部分,这里只讨论linux的内核部分。
linux内核是在unix基础上修改而来,在它里面,可以看到很多unix的影子。linux刚开始的时候,是按照宏内核的方式设计的,但到了现在,也 以经不是单纯的宏内核或是微内核了,应该是运用了两个的优点,现在成功的系统都是采用这种设计的。驱动部分采用了模块化的设计方案,整个内核也是一个多线 程来运行的,但内存管理,进程调度,进程管理等也是编译到一起的。所以它是一个混内核的方式。
我们来说说内核的编写语言吧,可能很多人会告诉你,一个程序,用什么语言都是差不多的,语言不是很重要的。我觉得语言的选择还是很重要的,要不这个世界就 不会存在这么多语言了,每个语言都是有自己的领域,有自己的适用范围的。linux的内核是用C语言来编写的。
之前有人问过我,为什么linux不是用C++来设计,是不是因为linux出来的时候,C++还没有出来,所以才保留着C语言。这个问题嘛,其实不是这 样的,C语言现在还有很多人用,并不是因为以前的人用C语言,而现在保留了下来。主要是因为C语言数年来,证明它的确是一门十分优秀的语言。你也不要同我 说C语言有什么缺点什么的,C++又多么好,不要拿这两种语言来比谁好谁坏,在操作系统方面,C语言的确要比C++更适合,面向对象在操作系统的设计上好 像也不太合适,还是面向过程的函数式编程比较适合,系统毕竟是相当靠近底层的了。效率上,当然也会更高一些。目前来说,我还不知道什么操作系统不是用C语 言来设计的,如果你发现了有,请给我留言,我是好奇心很强的人,也想填补一下这方面的空白。如果回答linux为什么不是用C++来设计的,有更简单的理 由,因为linus不喜欢C++,他一直在批评C++是一门多么不好的语言。
下面说说linux的启动过程,如有不对,请指出,linux的代码每天都在变,我的代码最近一次同步应该是2011年3月份,我 是按照我现在的代码来说。linux没有main函数,linux内核的入口在arch/alpha/kernel/head.S中,这还是汇编代 码,grub2结束后就跳到这里,这里简单设置一些全局变量后,开始跳到C语言的入口,就是大家最熟悉的start_kernel,在 init/main.c中,函数开始就先lock_kernel,这个时候还不可以接受中断请求,第一件事情当然是创建内核页表,映射所有物理内存和io 空间了,linux用的是页式内存管理,它里面的段式管理部分是没有作用的,只是i386的CPU设计成这样,这一步linux只是为了能让它在i386 之上能运行。linux不是一个段式内存管理或段页式内存管理的系统,它只是一个页式内存管理的方式。内核页表创建之后,就可以运行在保护模式之下了,这 下可就爽多了。接着是打印一些内核信息出来,也许你会问,系统这个时候能输出东西吗?对的,不可以,内核的printk有一个缓冲的概念,这个东西会先放 在内存里,等后面的驱动初始化之后,这个东西将会送到控制台里去。下一个是setup_arch,CPU体系结构初始化,用户写的程序,一般是CPU无关 的,很少上层的程序员写程序的时候会关心它的程序运行在什么CPU上的,最多就考虑一个大头小头的概念,intel系列都是小头的,我有过的CPU只有 PPC是大头的。但是在内核,代码可是CPU相关的。接下来就是setup_per_cpu_areas,为每个CPU分别初始化,linux可是支持多 CPU的,也是支持超级计算机的。sched_init初始化每个处理器的可运行进程队列,preempt_disable禁止内核抢 占,build_all_zonelists建立系统内存页区,下来是为内存申请做一些处理,为之后内存申请,现在的还不是虚拟内存的形式,下来是外部送 进来的一些参数解析,应该是grub2送过来的参数,然后是中断相关的一些初始化,pid的hash初始化,时间系统初始化,下来就可以打开中断请求了, 收受中断请求,虚拟文件系统,就是传说中的VFS,然后是内存初始化,现在开始就不用物理内存了,开始可以用虚拟内存了,然后创建进程相关初始 化,proc文件系统初始化,电源管理初始化,最后是准备调用用户空间的init程序,在2.6的内核里,如果不把initrd编译进内核的话,它里面也 有一个init程序,内核会先调用它,它会加载那些模块化的驱动程序,最后调用用户空间的init,内核就这样启动完成了,这里只列出了主要的初始化过 程,没有完全列出来,发现有点多。
下来说说文件系统吧,linux支持非常多的文件系统,有20种左右吧,是我认识的支持最多文件系统的一个内核。内核要访问所有文件系统,都必需经过虚拟 文件系统VFS,然后由VFS指向真正的文件系统,为什么要这样子设计呢,它有点像面向对象中的抽象部分,也有点像设计模式中的门面模式,由两层结构变成 3层结构,也就是外面访问是通过间接的方式,而不是直接方式,这样子设计更加灵活,对增加或减少一个文件系统是很方便的,这样子好像还可以动态接入。说到 动态接入,又想起了一个项目,fuse,一种能把文件系统写到用户空间的办法,看linux社区的讨论,这种方案可能会成为linux以后的发展方向。其 实看文件系统的代码时,不用每种都看的,基本上是差不多的,几乎都是通过superblock,inode,dentry来组织一个文件系统,linux 还可以在一个文件系统插入另一个文件系统的。文件系统就先简单这样子介绍一下,之后再专门写一篇文件来深入分析。
现在我们再说说系统调用吧,linux的系统调用的数目比较少,只有255个,而不像windows那么巨大,虽然我们不知道 windows到底有多少个,我觉得起码有1000个以上吧,API都有2520个左右了,系统调用能少吗?以前的系统调用都是通过像中断一样的办法,用 int 13(好像是这个,有空查查)这样的指令进入内核的,而现在系统,这个一般都不用了,都是通过快速系统调用而进入的内核空间的,记得是P3之后的CPU加 入了这个指令,速度上要比之前的方法快一些,因为它是不用处理栈的。流程大概是这样的:通过CRT中的API调用,最终把数据整理好,比如参数,还有系统 调用号,然后通过快速系统调用指令,跳到了内核空间的13号中断号的代码(好像是13,我就不查实确认了,记忆力不是很好)然后根据调用号到内核的系统调 用表中得到对应的处理函数。
内存管理是页式内存管理的方法,内核数据与代码不可以置换,这与windows有点不同,谁叫windows把图形服务也加入到内核,把内核靠得这么大。 linux内核应该算很小的,没有必要支持置换。linux内存分三个层次来管理,最上是主页表,好像是叫这个名字。内核占低1G的空间,所以进程共享, 高3G是进程单独占有,这个不像windows分别是2G。
进程调度方面,linux是抢占模式,中断的时候当然是不可以抢占的,具体实现,以后再讨论吧。这篇文章够长了,不想在这里讨论。
在安全方面,linux以权限的控制要比windows更加严格。