Back to Linux

See Also: Startup Process系统调用调度

Linux Kernel

Linux内核是一个类Unix操作系统内核。Linux内核是全球使用最广泛的操作系统内核;Linux操作系统是基于它,通常以Linux发行版的形式部署在传统的计算机系统上;嵌入式设备如路由器使用它;平板电脑和智能手机上的Android操作系统也是基于Linux内核基础之上的。

Linux内核最早是由芬兰计算机系学生林纳斯·托瓦兹构思和创建的,为尝试在英特尔x86架构上提供自由免费的类Unix系统而开发。该计划开始于1991年,林纳斯·托瓦兹当时在Usenet新闻组comp.os.minix登载帖子,这份著名的帖子标示着Linux计划的正式开始。

Linux内核API和用户程序与内核交互的应用程序编程接口(API),非常的稳定,不会中断用户空间程序。作为内核功能的一部分,设备驱动程序控制硬件;“主线”设备驱动程序也应该是非常稳定的。但是,内核和可加载内核模块(lkm)之间的接口没有很强的耦合,这与其他内核和操作系统的设计思路不同。

Linux内核是在GNU通用公共许可证第2版之下发布的(加上一些固件与各种非自由许可证)。贡献者遍布世界各地,日常开发在Linux内核邮件列表

https://turnoff.us/geek/inside-the-linux-kernel/

1. 历史

See also: Linux历史

2. 法律方面

2.1. 授权条款

最初,托沃兹发布的Linux授权禁止任何商业使用,而到了0.12版本,授权改为GNU General Public License(GPL)的许可。这种许可证允许发布和销售可能被修改及未修改的Linux版本,但要求所有这些副本在相同的许可证下被发布,并包含完整的源代码。

托沃兹认为把Linux许可在GPL下是自己做过的最好的事情。

2.1.1. GPL version 3

2.2. 固件争议

Linux使用固件二进制包以支持某些硬件设备。理察·马修·斯托曼认为这些东西让Linux某部份成为非自由软件,甚至以此散布Linux更会破坏GPL,因为GPL需要完全可获取的源代码[8]。

林纳斯·托瓦兹及Linux社区中的领导者,支持较宽松的许可证,不支持理察·马修·斯托曼的立场。社区中的Linux-libre提供完整的自由软件固件。

2.3. Linux的商标

Linux被Linus Torvalds在美国和其他一些国家进行了商标注册。

3. 架构

See also: http://en.wikipedia.org/wiki/Vmlinux

Linux是一个宏内核,设备驱动程序可以完全访问硬件。Linux内的设备驱动程序可以方便地以模块化(modularize)的形式设置,并在系统运行期间可直接装载或卸载。

Linux_Layers.png

如上图所示,最上面是用户(或应用程序)空间。这是用户应用程序执行的地方。用户空间之下是内核空间,Linux 内核正是位于这里。

GNU C Library (glibc)也在这里。它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间。每个用户空间的进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。

Linux 内核可以进一步划分成 3 层。最上面是系统调用接口,它实现了一些基本的功能,例如 read 和 write。系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码。这些代码是 Linux 所支持的所有处理器体系结构所通用的。在这些代码之下是依赖于体系结构的代码,构成了通常称为 BSP(Board Support Package)的部分。这些代码用作给定体系结构的处理器和特定于平台的代码。

3.1. vmlinux

在linux系统中,vmlinux(vmlinuz)是一个包含linux kernel的静态链接的可执行文件,文件型态可能是linux接受的可执行文件格式之一(ELF、COFF或a.out),vmlinux若要用于除错时则必须要在开机前增加symbol table。

3.2. 编写语言

Linux是用C语言中的GCC版(这种C语言有对标准C进行扩展)写的,还有几个用汇编语言(用的是GCC的"AT&T 风格")写的目标构架短段。因为要支持扩展的C语言,GCC在很长的时间里是唯一一个能正确编译Linux的编译器。在2004年,Intel主张通过修改内核,以便它的编译器能正确编译内核。在2009年,有通过修改内核2.6.22版而成功编译的报告(并带来平均8-9%性能增长)。

有许多其他的语言用在一些方面上,主要集中在内核构建过程中(这里指从源代码创建可启动镜像)。包括Perl,Python,和多种脚本语言。有一些驱动可能是用C++,Fortran,或其他语言写的,但是这样是强烈不建议的。 Linux的官方构建系统仅仅支持GCC作为其内核和驱动的编译器。

3.3. Interfaces

attachment:Linux_kernel_interfaces.svg

3.4. Kernel-to-userspace API

源代码可移植性确保了使用C程序写的、符合标准的源代码可以成功地编译和运行在任何也符合标准的系统。相关标准,旨在实现Linux内核开发源代码的程序可移植性,包括GNU C库,POSIX和单一UNIX规范。

Linux内核的API,代表了内核的系统调用接口,由可用的系统调用。

3.5. Kernel-to-userspace ABI

二进制可移植性应当保证任何程序一旦针对一个给定的硬件平台编译,编译后的二进制文件就可以运行在任何其他符合标准的硬件平台上。二进制可移植性是独立软件供应商(ISV)构建基于Linux内核的操作系统的应用程序的一个重要的商业指标。

二进制兼容性要比源代码可移植性要求更加苛刻;有关与二进制兼容性的唯一标准是Linux Standard Base(LSB)。

3.6. In-kernel API

3.7. In-kernel ABI

3.8. Technical features

3.8.1. Preemption

3.8.2. Portability

尽管林纳斯·托瓦兹的初衷不是使Linux成为一个可移植的操作系统,今天的Linux却是全球被最广泛移植的操作系统内核。从移动电话到超级电脑,甚至于有人成功的将Linux内核在索尼出品的游戏机PS2及PS3和微软出品的游戏机Xbox上使用。Linux也是IBM超级计算机Blue Gene的操作系统。全球前五百大超级电脑(TOP500)有高达91.4%的比例采用Linux为它们的操作系统。一些为手机开发的操作系统,使用Linux内核的修改后的版本,其中包括Google Android、Firefox OS、HP WebOS和诺基亚Maemo。

3.8.3. Kernel panic and oopses(恐慌和哎呀,类似错误和异常)

在Linux中,"panic"是内核检测到的一个不可恢复的系统错误,而"oops"是用户空间代码检测到的错误。内核代码有可能根据sys/system.h头文件调用panic函数来表明一个状态;然而大多数panic的原因是未处理的处理器内核代码中的异常,如:引用无效的内存地址。而通常导致panic的原因是表明在调用链中有bug;还可以因为硬件故障,比如失效的内存单元或算术函数失败错误、处理器bug、过热或损坏的处理器,或一个软件错误。

非致命错误的报告在内核中称为"oops";如果允许Linux内核继续这种偏离非正常行为继续,可能损害可靠性。这些事故报告被自动收集并可以通过各种软件进行上传,如kerneloops,ABRT(Fedora)和apport(Ubuntu)。KernelOops.org}}target="_blank"收集这些报告和统计数据在他们的网站上公布。

3.9. 安全性

计算机安全是一个非常公众化的主题,关系到Linux内核,因为大量在内核中的错误可能成为潜在的安全漏洞,是否允许提升权限漏洞或拒绝服务攻击源漏洞。在过去的几年中,许多这样的缺陷被发现,并在Linux内核中被修补好。新的安全功能被继续实现,以解决在Linux内核中的电脑不安全问题。

批评者指责内核开发人员,称他们掩盖(至少并未公布)安全漏洞。2008年,作为回应,Torvalds称:“个人认为,安全漏洞只是‘正常的漏洞’。这些漏洞我并不去掩盖,不过我不认为应当把它们特殊化,更不认为应该追踪并公示它们……我不理会整个安全团队,原因之一就是,我认为这些漏洞不仅美化还鼓励了错误的行为。这令安全人员成了‘英雄’,就犹如不修补正常漏洞的人就不值一提似的。而事实上,所有无聊的正常漏洞极为重要,仅仅因为它们实在太多了。我不认为该美化和关心那些严重的安全漏洞——它们并不及那些由死锁造成的随机严重崩溃来得更特殊。”

4. Linux内核子系统

http://oss.org.cn/kernel-book/

kernel_components.jpg

4.1. System Call Interface(系统调用接口)

SCI 层提供了某些机制,执行从用户空间到内核的函数调用。这个接口依赖于体系结构,甚至在相同的处理器家族内也是如此。SCI 实际上是一个非常有用的函数调用多路复用和多路分解服务。在 ./linux/kernel 中您可以找到 SCI 的实现,并在 ./linux/arch 中找到依赖于体系结构的部分。

常见的系统调用包括:

4.2. Process Scheduling Subsystem(进程调度子系统)

在计算机科学领域,调度是指线程、进程或数据流被授予访问系统资源(如处理器时间、通信带宽等)的方法。这样做通常是为了有效负载平衡和共享系统资源或实现要求的服务质量。

对现代系统调度算法的要求:

4.3. Inter-Process Communication Subsystem(进程间通讯子系统)

参考: https://www.kernel.org/doc/htmldocs/kernel-api/ipc.html

IPC进程间通信(Inter-Process Communication)就是指多个进程之间相互通信,交换信息的方法。Linux IPC基本上都是从Unix平台上继承而来的。主要包括最初的Unix IPC,System V IPC以及基于Socket的IPC。另外,Linux也支持POSIX IPC。

4.3.1. 进程管理

进程管理的重点是进程的执行。在内核中,这些进程称为线程,代表了单独的处理器虚拟化(线程代码、数据、堆栈和 CPU 寄存器)。在用户空间,通常使用进程这个术语,不过 Linux 实现并没有区分这两个概念(进程和线程)。内核通过 SCI 提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或 Portable Operating System Interface [POSIX] 函数),停止进程(kill、exit),并在它们之间进行通信和同步(signal 或者 POSIX 机制)。

进程管理还包括处理活动进程之间共享 CPU 的需求。内核实现了一种新型的调度算法,不管有多少个线程在竞争 CPU,这种算法都可以在固定时间内进行操作。这种算法就称为 O(1) 调度程序,这个名字就表示它调度多个线程所使用的时间和调度一个线程所使用的时间是相同的。 O(1) 调度程序也可以支持多处理器(称为对称多处理器或 SMP)。您可以在 ./linux/kernel 中找到进程管理的源代码,在 ./linux/arch 中可以找到依赖于体系结构的源代码。

4.4. Memory Management Subsystem(内存管理子系统)

内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页方式进行管理的(对于大部分体系结构来说都是 4KB)。Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。

不过内存管理要管理的可不止 4KB 缓冲区。Linux 提供了对 4KB 缓冲区的抽象,例如 slab 分配器。这种内存管理模式使用 4KB 缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页是满的,哪些页面没有完全使用,哪些页面为空。这样就允许该模式根据系统需要来动态调整内存使用。

为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上。内存管理的源代码可以在 ./linux/mm 中找到。

4.5. Virtual Files Subsystem(虚拟文件子系统)

虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层。

virtual_file_system.jpg

文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。

4.6. Network Subsystem(网络子系统)

网络堆栈在设计上遵循模拟协议本身的分层体系结构。回想一下,Internet Protocol (IP) 是传输协议(通常称为传输控制协议或 TCP)下面的核心网络层协议。TCP 上面是 socket 层,它是通过 SCI 进行调用的。

socket 层是网络子系统的标准 API,它为各种网络协议提供了一个用户接口。从原始帧访问到 IP 协议数据单元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 层提供了一种标准化的方法来管理连接,并在各个终点之间移动数据。内核中网络源代码可以在 ./linux/net 中找到。

4.7. 设备驱动程序

Linux 内核中有大量代码都在设备驱动程序中,它们能够运转特定的硬件设备。Linux 源码树提供了一个驱动程序子目录,这个目录又进一步划分为各种支持设备,例如 Bluetooth、I2C、serial 等。设备驱动程序的代码可以在 ./linux/drivers 中找到。

4.8. 依赖体系结构的代码(Architecture-dependent code)

尽管 Linux 很大程度上独立于所运行的体系结构,但是有些元素则必须考虑体系结构才能正常操作并实现更高效率。./linux/arch 子目录定义了内核源代码中依赖于体系结构的部分,其中包含了各种特定于体系结构的子目录(共同组成了 BSP)。对于一个典型的桌面系统来说,使用的是 i386 目录。每个体系结构子目录都包含了很多其他子目录,每个子目录都关注内核中的一个特定方面,例如引导、内核、内存管理等。这些依赖体系结构的代码可以在 ./linux/arch 中找到。

5. 开发

5.1. 发布版本

See also: http://en.wikipedia.org/wiki/Linux_kernel#Maintenance

5.1.1. Longterm Maintenance

通常有几个内核是“长期维护”版本,这个内核中发现的bug也会不断进行修复。不过这种版本通常不会频繁的发布,只有非常重要的修正才会应用于这样的内核,特别是对于更老的版本。

https://www.kernel.org/category/releases.html

5.2. 基于Linux的服务

LAMP_software_bundle.svg

6. Reference


CategoryLinux

MainWiki: Linux_Kernel (last edited 2009-09-29 00:30:53 by twotwo)