图书前言

20年前诞生于学生之手的Linux,借助于Internet这片肥沃的土壤,在开源文化的大熔炉中,逐步成长为穿越桌面、服务器以及智能终端的通用操作系统。

1991年那个稚嫩的0.01版就是Linus在操作系统课上写的一个大作业,翻看其代码,调度程序也就三十多行,文件系统的读写函数各只有十多行(不含所调用的其他函数),如此而已,初学者可以在这样的代码中看到自己所写程序的影子。

Linux从曾经的0.01版到现在的3.0版,历经了八百多个版本的变迁,其中变化的点滴都记录在Linux内核邮件列表(LKML)中,从这些足迹中,我们会寻觅到一个变量为什么那样定义,一个结构体为什么要增减字段,一个函数的参数为什么从三个变为两个,在这一个个的细节中,软件设计的蛛丝马迹也就逐步展现出来。但是,这些过往的信息是海量的,多本教材都无法容纳,需要读者进行大量的课外阅读。

Linux内核的全部源代码是一个庞大的世界,如何在这庞大而又复杂的世界中抓住主要内容,如何找到进入Linux内部的突破口,又如何把Linux的源代码变为自己所需,并在此基础上进行内核级程序的开发,这是本书要探讨的内容。

首先第1章概述从不同侧面概要描述了大家熟悉而又陌生的操作系统,使读者从宏观上对操作系统有一个初步认识。之后,简要介绍了Linux的同族同源UNIX,从而说明Linux赖以生存的土壤源于三十多年UNIX的发展。为了让读者对Linux有初步了解后动手实践,本章还介绍了Linux内核中的模块编写方法,并以链表为入口点,让读者近距离感知Linux内核代码设计中的精彩和美妙。

第2章内存寻址从寻址方式的演变入手,给出与操作系统设计密切相关的概念。比如,实模式、保护模式、各种寄存器、物理地址、虚拟地址以及线性地址等。然后对保护模式的分段机制和分页机制简要描述,并从Linux设计的角度分析了这些机制的具体落实。接着介绍了Linux中的汇编以及嵌入式汇编,最后给出了Linux系统的地址映射示例,这是在第2章就引入内存寻址的根本目的,就是操作系统如何借助硬件把虚地址转化为物理地址。

第3章进程从进程的引入开始,阐述了进程的各个方面,包括进程上下文、进程层次结构、进程状态,尤其是对进程控制块进行了比较全面的介绍。task_struct结构作为描述Linux进程的核心数据结构,对其熟悉和掌握可深入了解进程的入口点。另外,进程控制块的各种组织方式链表、散列表、队列等数据结构是管理和调度进程的基础。在这些基础上,对核心内容进程调度进行了代码级的描述,并给出了Linux新版本中改进的方法和思路。最后,以进程系统调用的剖析和应用结束本章。

第4章内存管理主要围绕虚地址到物理地址的转换,由此引发出了各种问题,比如地址映射问题,一方面把可执行映像映射到虚拟地址空间,另一方面把虚地址空间映射到物理地址空间。而在程序执行时,涉及请页问题,把虚空间中的页真正搬到物理空间,由此要对物理空间进行分配和回收,而在物理内存不够时,又必须进行内外交换,交换的效率直接影响系统的性能,于是缓冲和刷新技术

应运而生。本章最后一节给出了一个比较完整的例子,说明内存管理在实际中的应用。

第5章中断和异常涵盖了较多的概念: 中断和异常、中断向量、IRQ、中断描述符表、中断请求队列、中断的上半部和下半部、时钟中断、时钟节拍、节拍率、定时器等。中断使得硬件与处理器进行通信,不同的设备对应的中断不同; 同时,不同的中断具有不同的中断服务程序,其中断处理程序的入口地址存放在中断向量表中。当某个中断发生时,对应的中断服务程序得到执行,在执行期间不接受外界的干扰。为了缓解中断服务程序的压力,内核中引入了中断下半部机制,其本质都是推后下半部函数的执行。时钟中断是内核跳动的脉搏,本章引入了时钟节拍、jiffies、节拍率等概念,简要介绍了时钟中断的运行机制,同时给出了定时器的简单应用。

第6章系统调用是内核与用户程序进行交互的接口。本章从不同角度对系统调用进行了描述,说明了系统调用与API、系统命令以及内核函数之间的关系。然后,分析了Linux内核如何实现系统调用,说明系统调用处理程序以及服务例程在整个系统调用执行过程中的作用。最后,通过两个实例讨论了如何增加系统调用,并给出了从用户空间调用系统调用的简单例子。本章最后的日志收集系统实例给出了完整的过程,以便读者充分认识系统调用的价值并在自己的项目开发中灵活应用。

第7章内核同步首先介绍了临界区、共享队列、死锁等相关的同步概念,然后给出了内核中常用的三种同步方法,即原子操作、自旋锁以及信号量,其中对信号量的实现机制进行了稍微深入的分析。为了加强读者对同步机制的应用能力,本章给出了两大实例,其一是生产者消费者模型,其二是内核中线程、系统调用以及定时器任务队列的并发执行。通过这两个例子,让读者深刻体会并发程序编写中如何应用同步机制。

第8章文件系统首先介绍了文件系统的基础知识,其中涉及索引节点、软连接、硬链接、文件系统、文件类型以及文件的访问权限等概念。虚拟文件系统机制使得Linux可以支持各种不同的文件系统,其实现中涉及的主要对象有超级块、索引节点、目录项以及文件,对这些数据结构的描述可以使读者深入到细节了解具体字段的含义。然后,简要讨论了文件系统的注册、安装以及卸载,最后的实例给出romfs文件系统的具体实现。

第9章设备驱动首先阐述了设备驱动程序在文件系统中所处的位置。接着介绍了驱动程序的通用框架,以及Linux字符驱动的简单实例,让读者对驱动程序有一个初步认识。然后对设备驱动开发中所涉及的I/O空间进行了比较详细的介绍。在字符设备驱动一节,把内存空间的一片区域看做一个字符设备,并给出了开发这样一个驱动程序的具体步骤和过程。最后,对块设备驱动程序的开发给出了简要描述。

为了突出主题,本教材尽量简化相关内容,但为了填补课堂教学和实践开发之间的鸿沟,我们在Linux内核之旅www.kerneltravel.net网站上发布了与内核相关的学习资料。针对读者学习操作系统课程后,苦于无用武之地的现状,网站上讨论了如何进行Linux内核层面上的系统软件开发,并配以有实用价值或指导意义的实验。

在近几年的教学过程中,依然感到学生对Linux系统的陌生和动手能力偏弱,针对这种现状,在本次改版过程中,尽量从Linux命令级入手,逐步过渡到原理; 从简单的小实验入手,逐步过渡到大例子,以便学生把所学原理与平时遇到的问题联系起来。

由于本教材的篇幅所限,本书内容进行了一定的简化,这可能在某种程度上影响了读者对其内容的深入理解,为此,Linux内核之旅网站公布了作者曾经编写的《深入分析Linux内核源代码》一书的电子版内容,以满足读者深入探究之愿望。

在本次内容的改编过程中,得到了很多学生的支持,他们是许振文、牛涛、陈继峰、武婷、武特等,而武特的博客http://edsionte.com/techblog/更是让初学者有一种亲近感和熟悉感, 希望大家在学习的过程中,以博客的形式分享自己的心得。

作者

2011年9月