LKD 总结 —— 第一章

Unix 的优点

Linux 承袭了大量 Unix 的设计精华主要包括下面这些:

  • 系统接口简单,也就是说系统调用设计的很合理

  • 一切都是文件,这样就可以把数据和设备的访问统一到 open(), read(), write(), lseek(), close() 这组系统调用中

  • 使用 C 语言编写,有非常好的可移植性(这个应该是相对与汇编语言来说吧)

  • 快速的进程创建(fork)

  • 简单而稳定的进程间通信机制(IPC)

操作系统和概述

操作系统严格意义上来说指的只是它的内核、用户接口而不包括在上面运行的程序(不过个 人认为操作系统存在的意义就是让这些程序跑起来完成用户想要完成的工作)。在一个操作 系统中用户接口在最外层用来和用户进行交互,而在最内层提供基础服务的是内核。

内核主要由以下几部分组成:中断处理处理器、进程调度器、内存管理系统,网络服务、 IPC 等等。内核代码运行在内核空间(kernel-space),而用户程序运行在用户空间( user-space)。内核空间和用户空间的概念需要日后慢慢理解,在 ULK(Understanding Linux Kernel) 里面提到了 CPU 有不同的工作模式,包括特权模式和非特权模式等,而内 核代码一般运行在特权模式,用户程序则运行在非特权模式,这种两个模式又被成为内核模 式(kernel mode)和用户模式(user mode)。内核空间和内核模式应该不是指的同一个概 念,在维基百科上的解释说虚拟地址空间分为内核空间和用户空间,这种解释应该是比较合 理的。

内核对上层来说,它给用户程序提供了系统调用。用户程序通过使用系统调用而陷入到内核 中执行内核代码,此时系统从用户空间切换到内核空间,而内核运行在进程上下文中(相对 于下文中的中断上下文)。对下层来说,内核需要管理系统中的硬件,这是通过中断来实现 的。当中断发生之后,系统执行中断处理器。此时系统在内核空间运行(运行的内核代码) 并且内核处于中断上下文。

任何一个时刻,处理器都只可能处于以下三种状态之一:

  • 在用户空间,执行进程代码

  • 在内核空间的进程上下文中执行内核代码(执行系统调用,此时内核其实是在替进程执行 代码,因为严格意义上来说系统调用是进程代码执行中的一步,属于这个进程的代码)

  • 在内核空间的中断上下文中,处理中断(没有相关的进程,这是很重要的一点,没有相关 的进程也就意味着不能够阻塞,不能睡眠,无法调度)

所以其实内核并没有无时不刻的在运行。在第一种情况下执行的是用户代码,而后面两种情 况执行的是内核代码(一个处理器不可能同时执行两条指令,所以说上面三种情况是互斥的 ,操作系统在一直运行但并不表示它的内核在一直运行)。

宏内核和微内核

这两种内核的争论从来没有停过,操作系统大神塔能鲍姆(学术派——微内核派)和林纳斯( 实用派——宏内核派)就哪种内核好有过激烈的争论。宏内核,所有的内核代码都在一个地址 空间运行,内核间的交互可以通过简单的函数调用来完成,高效而简单,基本上所有的 Unix 都是宏内核(当然也包括它的后继者 Linux)。而微内核在学术上来说是非常美的设 计,内核的功能被分配给不同的进程(通常称为服务),也就是说内核代码运行在不同的地 址空间,服务间交互是通过 IPC 来完成的。理论上只有核心的服务需要运行在内核空间, 而其他的服务可以在用户空间运行,这可以大大的提供系统的健壮性(一个服务终止不会影 响其他的服务),也可以很好的实现模块化,同时不必要的服务也可以销毁节省空间。但是 在实际中,IPC 不但开销非常大也没有函数调用的高效性,同时为了减少在用户空间和内核 空间中的切换,目前的微内核都把服务放在内核空间(这就有违设计初衷)。

Linux 向来都是实用至上。它虽然是宏内核,但是它支持模块的动态加载,从而支持模块化 ,它也支持内核线程(类似于微内核的服务概念),此外内核本身是可抢占的,也就是可以 调度的(这类似微内核不同的服务之间可以调度)。这种设计融合了微内核和宏内核的优点 ,既没有微内核的开销又可以实现模块化。

Linux 独有的特点

Linux 并不是 Unix 的直系后代,对于任何问题它都可以选着最佳的实践方案而不用考虑向 后兼容的问题(新建一套房子要比整修一套房子简单)。Linux 选着一个解决方案的标准在 于是否有合理的设计和优雅的实现,而不是在于它听上去美不美。

Linux 内核版本

在书本上提到的版本号和目前使用的似乎不太一样,书本中的版本号如下:

2.6.26.1

第一个数字是主版本号,第二个为次版本号。次版本号决定内核版本是否是稳定的。如果次 版本号为偶数表示稳定否则是开发版本。版本号的前两位组成一个内核系列如 2.4 系列。 第三个数字表示版本修正,是在一个内核系列中(如 2.4 系列)因为BUG 修复、新驱动和 新特性的加入而发布的新版本(2.4.1)。同一系列相邻的修正号之间一般不会有太大的变 化。

但是这一方案在 2004 出现了变化。2.6 序列的开发周期无限延长,前面三位数字组成一个 小的迷你开发序列,如 2.6.26 序列。相邻的两个小的序列中可能会出现非常大的变化。因 为开发周期很长,比如 2.6.26 这个序列的开发周期可能长达数月,出现了严重的 BUG 需 要更新版本号的时候使用第四个数字(比如:2.6.26.1 中的 1,这有点像原来方案中的修 正号),这个 BUG 通常是目前的版本(这个例子中是 2.6.27)对上一个版本的 back-port 。

当前的版本号和书上的有了较大的不同。林纳斯已经成功把内核版本号从冗长的 2.6 直接 跳到了 3.0 (借口是内核发布 20 周年,为了升级版本号他可以说是煞费苦心,网上有这 一段有趣的故事,大家可以去看看,从中可以看出开源和不开源的区别[^1]),目前内核版 本演化到 3.17,目前的版本分为: Prepatch、Mainline、Stable、Longterm 四种而不是 稳定和开发两种[^2],也没有再出现三位数的迷你开发序列。


[^1]: 林纳斯它虽然创造了 Linux 它也拥有 Linux 的商标,但是它没有权利觉得 Linux 的走向。Linux 到底会如何发展还是看社区的全体开发者的决定

[^2]: 目前到版本号也没有使用次版本号到奇偶性来区分稳定和不稳定,比如目前最新到 Stable 版本是 3.17.1 (2014-10-22)