标题：UNIX技术内幕
图书信息
书名：返璞归真——UNIX技术内幕  作者：郝庆丰  编著
ISBN 978-7-121-10871-6 
出版日期：2010年6月 
定价：89.00元(含CD光盘1张)　
开本：16开 
页码：768页
宣传语
节选10000行UNIX内核源码
耳目一新的视角
入木三分的剖析
生动详尽的图例
作者实现的线程
恰似醍醐灌顶，让你彻底了解UNIX内核。
内 容 简 介
操作系统是一种对计算机中各个设备和资源进行管理并给应用软件提供各种服务的系统软件，它的实现可分用户态和内核态两大部分。一般而言，操作系统的算法和设计的复杂性大多在内核态部分。因此，了解操作系统的内核实现对于了解整个操作系统是非常重要的。
本书内容非常易于读者理解。选择UNIX作为讲解对象是因为它强大的生命力和应用的广泛性。在精妙的设计思想下，它具有小巧高效而健壮的内核、丰富的功能、易扩展的架构和良好的开放性。UNIX所定义的很多接口（比如文件访问接口）已经成为行业标准。本书在讲解时，作者把这10 000行代码按照不同的功能模块分成不同的章节。每章一般最小以函数为单位，但在讲解某个功能或接口时，又会牵涉到很多相关的函数，并其中揭示了很多优秀的设计思想、数据结构和算法。
初级软件开发人员在阅读本书时可能会碰到一些困难，但如能坚持研究，它也会是你提高编程水平的一个很好的选择。
序  一
操作系统作为计算机中核心的系统软件，直接决定了计算机系统的整体性能。学习操作系统的过程中，理解所有操作系统设计背后的原理是非常重要的，但如果能够把这些原理和真实的操作系统实现结合起来，则可以更加深刻地理解操作系统的本质所在。
美国贝尔实验室的丹尼斯·里奇（Dennis Mac Alistair Ritchie）和肯尼思·汤普森（Kenneth lane·Thompson）共同开发的C和UNIX是本领域最重要的成果之一，对整个计算机产业产生了深远的影响。因此，通过深入分析阅读UNIX这一经典系统的源代码实现来学习操作系统是非常有价值的途径。UNIX 第6版（UNIX V6）是现代各类UNIX操作系统的源头，它具备了现代操作系统的绝大部分特征：进程管理和调度、内存管理、文件系统和I/O设备管理等。在此之后，UNIX分为众多不同流派，但它们基本上都秉承了UNIX V6的设计思想。
作者郝庆丰曾在朗讯、摩托罗拉等公司从事多年的软件开发工作，参与过多个UNIX及Linux下大型软件项目的设计和开发，有着数十万行代码的开发经验。基于这些基础，他编写了这本讲解UNIX的书籍，针对PDP-11处理器，给出UNIX V6近万行源码的详细解析，其中也包含了很多作者自己的开发经验和理解。在写作过程中，作者翻阅了大量资料，做了很多实验。因此，书中深入浅出、详略得当的讲解使得某些原本艰涩难懂的代码变得生动活泼，甚至妙趣横生。对于重点章节或很艰深的部分，作者则不吝笔墨、列举多个例子阐明；在每章结束还有针对性地提出一些思考题，让读者进一步巩固本章内容。
全书共分15章。第1章主要讲述UNIX诞生的经过、流派和它的特点。第2章主要讲述UNIX框架及其运行的硬件平台。第3章讲述虚拟内存的主要功能及UNIX虚拟内存的实现原理。第4章主要讲述启动过程。第5章主要讲述进程管理和调度的实现。第6章是对中断处理过程的讲解，而第7章讲述和中断类似的自陷的处理过程。第8章讲解文件系统，其实是文件系统的内核实现，而用户实现部分在第12章讲述。第9章讲解UNIX是如何管理I/O（输入/输出）设备的。第10章在第4章的基础上更全面地阐述UNIX的交换过程，因为交换是进程管理中一个很重要的概念。第11章讲述UNIX可执行文件的格式。第12章讲述UNIX系统调用的实现过程，包括了文件系统、进程和信号等部分。第13章不仅讲解已有的各种进程间通信的方式（信号、文件、管道），而且还给出其他多种进程间通信方式（信号量、互斥体、消息等）的示例实现。第14章给出现代操作系统才有的线程的示例实现。最后第15章讲述UNIX的登录过程和20世纪80年代出现的网络文件系统NFS，进而体现其对网络多用户的支持。
本书适用于具有丰富开发经验特别是想了解操作系统实现或对其感兴趣的软件工程师。
对于初级软件工程师，只要能认真研习，它也将是你提高软件开发水平的一个很好的选择。
清华大学计算机系教授、博士生导师  郑纬民
2010年4月15日于北京清华园
序  二
UNIX操作系统，诞生于四十余年前，作为一种革命性的软件产品，一直标示着软件业的顶尖水准。而UNIX 第6版，作为UNIX最后一个开放源码版本，历来是学习UNIX的最佳起点——这是中科院的必修课程，是麻省理工研究生院的必修课程。本书就是这样一本阐述其实现结构的巨著，它选择了UNIX第6版作为讲解对象，由框架到细节、由基础到高级，细述了各部分的实现和代码组成。
本书作者曾在朗讯、摩托罗拉等公司从事多年的软件开发工作，在UNIX及Linux平台下下有着非常丰富的开发经验，并对操作系统有着深入的研究。本书是作者在对UNIX第6版的每一行代码做了精心研究后所得出的理解和体会，是翻阅参考大量资料和实验验证的产物。正因为如此，本书中那些深入浅出、详略得当的讲解使得原本艰涩难懂的代码变得生动，甚至拍案叫绝。对于重点章节或晦涩的部分，作者不吝笔墨、列举多个例子予以阐明，例如第12章中对ptrace系统调用的解释，甚至给出了一个简单调试器（debugger）的实现。而对于相对次要或容易理解的部分，则一带而过，点到为止。值得称道的是，某些章节还例举大众熟知的Windows操作系统作为对比，以起到举一反三、融会贯通的效果。比如第8章就把UNIX文件系统实现和Windows FAT16做了比较，列举了各自的优劣所在。
作为本书的技术审校者，我是以学习的态度来阅读本书的。虽然我有着近二十年的操作系统与数据库工作经验，也常被封为所谓“技术专家”，但本书作者对UNIX入木三分的观点阐明使我受益颇深。更使我感动的是，作为一个真正的技术专家，作者对细节的处理态度——字字点到，句句说明！我们如何能不受益于这本书？
十年磨一剑，这是我对这本书的最真实感受！
不忍释手，一气读完，抬首看窗外，夜幕正在散去，黎明正在到来。回想我读的这本UNIX 6，正像是早晨的丝丝光线，它带我们穿越了繁杂的代码黑幕，揭示了UNIX的内部结构和来龙去脉，带给我们清晰的思想和逻辑！它能让我们拥有自信来掌握它、控制它，而不仅仅是对UNIX的顺从！
在Linux火热的今天，在UNIX大行其道的今天，让我们再上一步，给自己做一次“升级”，从一个低层次的代码堆砌者，成为一个有自己独立思想的系统架构师！
如果这样的程序员多了，中国怎能长时间地跟随欧美的脚步？更如何能走在印度后面？
感谢作者!
UNIX与数据库技术专家  侯文平
2010年4月于北京
前  言
自计算机诞生以来，产生了数以百计的操作系统，但这其中，无疑以UNIX最具有生命力，流派也最广。虽然在个人电脑上，Windows占据了绝大多数用户，但在服务器领域，UNIX依然是一枝独秀。Linux作为UNIX一个杰出的分支，已异军突起，不仅在服务器行业占有重要地位，而且在个人电脑上也越来越多地看到它的身影。
为什么UNIX具有如此强大的生命力？原因就在于它精妙的设计思想、小巧高效而又健壮的内核、丰富的功能、易扩展的架构和良好的开放性。UNIX所定义的很多接口（比如文件访问）已经成为行业标准，而它的分支也十分众多，如Unixware、AIX、Solaris、BSD UNIX等。
UNIX最早是由贝尔实验室（Bell Labs）的Kenneth Thompson （肯尼思·汤普森）和   Dennis Ritchie（丹尼斯·里奇）开发的，在此过程中，他们还发明了C语言。在1972年他们推出了UNIX版本6（UNIX 6 Edition），这也是本书所要讲述的版本。
本书内容
本书节选了UNIX版本6的全部内核代码及少量用户部分代码，总计在10 000行左右。之所以选择它是因为这是贝尔实验室所开放的最后一版UNIX，而且相对于前几版，它更贴近于现代操作系统，几乎具备了现代操作系统的所有概念：如中断和自陷管理、进程调度、内存管理、文件系统、I/O设备管理等。而且，很多现在的常用命令当时也已实现，比如mkdir、ls、cd、exec、find、grep、cron等。另外，本版90%代码都使用C语言编写，代码量也不大，这就使得阅读更加方便，适合讲解。
作者在讲述代码时，不仅尽量忠于和体现原来的设计思想，而且对于某些可能不太完美的实现部分还相应指出并给出改进的意见。此外，对于UNIX版本6不具备的某些功能，比如进程间互斥、消息通信和线程功能，作者还在第13章、第14章给出了简单的示例实现。另外，作者在列举源代码时，都在之前指明其所在文件，个别地方未指明的，在最近一次所指明的文件中。
本书读者
本书适用于有志于操作系统研究或对操作系统实现感兴趣的软件工程师，也可作为本专科院校计算机及相关专业学生学习操作系统和C语言的参考书。而对于其他软件人员，本书也将是你提高编程水平的一个很好的选择，书中揭示了很多优秀的设计思想、数据结构和算法，相信它们能给你以不少启示，在此过程中你还能看到C语言所展示出的精练高效的强大魅力！书中的很多代码后来也成为C程序标本式的实现和风格。
本书光盘
本书附有光盘，光盘不仅包含书中所列代码（包括作者自己实现的部分），还包含其他很多代码，比如init进程、shell进程等的实现。此外，还包括shell所支持的各个命令的实现代码，甚至还包含了当时所用的编译器。
读者可以直接阅读本书，也可以打开光盘中的代码，对照本书阅读。另外，在阅读时，有些章节如果联系起来看效果会更好，比如第4章和第5章、第6章和第9章。
版权声明
第13章和第14章中作者所实现部分的代码，由于环境限制，并未经过实际测试，对它们所造成任何可能的损坏性后果，作者在此声明并不对此负责，敬请谅解。另外，该部分代码只限于个人学习研究使用，作者保留对该部分代码的一切发布、发行、使用、修改及拷贝的权利，如有任何个人或组织要将其用于商业目的，请和作者联系并支付相应费用。
联系方式
由于作者水平所限，书中难免存在不当甚至错误之处，敬请批评指正。同时，非常欢迎读者提问、评论、批评和建议，可以和我联系。
IBM高级软件开发工程师  郝庆丰 
2009年8月于北京
目  录
第1章  概论    1
1.1  历史背景    1
1.2  UNIX诞生的经过    1
1.3  UNIX版本6    2
1.4  各流派一览    2
1.5  为什么取得成功    3
1.5.1  简洁高效    3
1.5.2  健壮性    3
1.5.3  功能丰富    3
1.5.4  移植性    3
1.5.5  开放性    4
1.6  缩写及术语说明    4
第2章  UNIX综述    6
2.1  硬件平台    6
2.1.1  中断和自陷（Trap）    7
2.1.2  两种处理器模式    9
2.1.3  通用寄存器    10
2.1.4  I/O设备管理    10
2.1.5  栈（Stack）    11
2.1.6  常用指令    11
2.1.7  备注    19
2.2  UNIX内核综述    20
2.2.1  模块分类    20
2.2.2  各模块间的通信    20
2.2.3  源文件    21
2.2.4  语法规则和编码风格说明    23
2.3  思考题    27
第3章  虚拟内存    28
3.1  简介    28
3.2  虚拟内存的优点    29
3.2.1  安全性    29
3.2.2  提高空间利用率    30
3.2.3  多进程的支持    30
3.3  PDP11/40的虚拟内存机制    30
3.3.1  页地址寄存器（PAR）    32
3.3.2  页描述寄存器（PDR）    32
3.3.3  活动页寄存器地址    33
3.3.4  虚拟地址向物理地址的映射过程    33
3.3.5  异常处理    35
3.3.6  和现代页式虚存的比较    36
3.4  UNIX的虚存实现    36
3.4.1  进程空间分布    36
3.4.2  用户活动页寄存器设置函数estabur    37
3.4.3  用户空间映射函数sureg    41
3.5  内存管理    42
3.5.1  内核内存管理    42
3.5.2  用户内存管理    47
3.6  思考题    56
第4章  启动模块    57
4.1  操作流程    57
4.2  中断向量    58
4.3  启动函数start    60
4.4  备注    65
4.4.1  为什么需要引导程序和装入程序    65
4.4.2  0地址处指令分析    65
4.4.3  为什么要使用汇编语言    66
4.4.4  Windows启动过程浅析    66
4.5  思考题    67
第5章  进程管理和调度    68
5.1  程序员眼中的虚拟机    68
5.2  系统资源    68
5.3  进程上下文    70
5.4  进程调度    72
5.5  UNIX实现    73
5.5.1  进程上下文    73
5.5.2  进程的两种状态    80
5.5.3  调度过程    82
5.5.4  备注    128
5.6  思考题    134
第6章  中断处理过程    136
6.1  PSW寄存器    136
6.2  中断处理流程    136
6.3  中断向量    138
6.4  PDP 11/40的中断类型    139
6.4.1  电传终端接口输入中断    139
6.4.2  电传终端接口输出中断    140
6.4.3  纸带打孔机输入中断    140
6.4.4  纸带打孔机输出中断    140
6.4.5  时钟中断    140
6.4.6  行打印机中断    140
6.4.7  磁盘读写中断    140
6.5  一些常用函数    140
6.5.1  特殊指令    140
6.5.2  fubyte(fuibyte)    141
6.5.3  fuword(fuiword)    143
6.5.4  subyte(suibyte)    143
6.5.5  suword(suiword)    144
6.5.6  clearseg    144
6.5.7  copyseg    145
6.5.8  copyin/copyout    146
6.5.9  dpadd    148
6.5.10  ldiv/lrem/lshift    148
6.6  call函数    149
6.7  时钟中断    151
6.7.1  基本概念    151
6.7.2  处理过程    152
6.8  call函数调用分派切换器的理由    163
6.9  内核定时器    164
6.9.1  数据结构    164
6.9.2  定时器的创建    165
6.9.3  定时器的触发    167
6.10  一些例子    168
6.10.1  进程优先级的调整    168
6.10.2  进程分派切换实例    174
6.11  备注    178
6.11.1  中断服务函数中为什么不使用互斥锁    178
6.11.2  中断服务函数中为什么不访问u变量    178
6.11.3  关于内存管理违例自陷的处理过程    179
6.11.4  调度标志runrun和runin    179
6.12  思考题    179
第7章  自陷    180
7.1  自陷原理    180
7.2  自陷向量    180
7.3  PDP11/40的自陷类型    180
7.3.1  系统出错自陷    180
7.3.2  系统调用自陷    182
7.3.3  调试自陷    182
7.3.4  自陷优先级    183
7.4  自陷处理过程    184
7.4.1  汇编函数_trap    184
7.4.2  C函数trap    186
7.4.3  backup函数    191
第8章  文件系统    211
8.1  概述    211
8.2  框架    212
8.2.1  文件存储的实现    212
8.2.2  UNIX文件系统    219
8.2.3  UNIX文件系统的详细实现    224
8.3  文件访问接口    229
8.3.1  文件创建接口creat    230
8.3.2  文件打开接口open    235
8.3.3  文件关闭接口close    236
8.3.4  文件读接口read    237
8.3.5  文件写接口write    238
8.3.6  文件定位接口seek    239
8.3.7  特殊文件创建接口mknod    242
8.3.8  文件链接接口link    244
8.3.9  取消文件链接接口unlink    246
8.3.10  设备加载接口smount    248
8.3.11  设备卸载接口sumount    251
8.4  节点和块管理    253
8.4.1  节点缓存    253
8.4.2  块缓存    255
8.4.3  块访问接口    263
8.4.4  节点访问接口    294
8.5  块设备驱动    322
8.5.1  概述    322
8.5.2  根设备——rk11磁盘    326
8.6  备注    335
8.6.1  FAT16文件系统    335
8.6.2  多进程访问文件的问题    338
8.6.3  进程间同步    339
8.6.4  文件的删除    340
8.6.5  设备驱动的扩展    340
8.7  总结    341
8.8  思考题    341
第9章  字符设备驱动    342
9.1  交互终端——电传打字机（teletypewriter）    342
9.1.1  设备特性    343
9.1.2  操作寄存器    343
9.1.3  驱动框架    345
9.1.4  驱动函数    351
9.1.5  shell应用举例    378
9.1.6  内核打印接口    379
9.2  PC-11纸带打孔机    383
9.2.1  设备特性    383
9.2.2  操作寄存器    384
9.2.3  驱动框架    385
9.2.4  驱动函数    387
9.2.5  读取器状态转换图    392
9.3  LP-11行打印机    393
9.3.1  设备特性    393
9.3.2  操作寄存器    393
9.3.3  驱动框架    394
9.3.4  驱动函数    396
9.4  现代打印机    401
9.4.1  并口    401
9.4.2  和内核挂接    403
9.4.3  简单的打印程序    406
9.4.4  CUPS    408
9.5  其他字符设备    408
9.5.1  内存    409
9.5.2  磁盘    411
9.6  网络驱动程序    415
9.7  综合示例    416
9.8  总结    417
9.9  思考题    418
第10章  进程交换过程    419
10.1  概述    419
10.2  具体实现    421
10.2.1  进程换出函数xswap    422
10.2.2  程序段内存释放函数xccdec    423
10.2.3  交换函数swap    424
10.2.4  调用实例    425
10.3  综合示例    426
10.4  思考题    430
第11章  UNIX可执行文件    431
11.1  .out文件    431
11.1.1  可执行头    431
11.1.2  程序段    432
11.1.3  数据段    432
11.1.4  程序和数据重定向表    432
11.1.5  符号表    434
11.1.6  示例    437
11.2  动态链接过程*    442
11.2.1  静态共享    443
11.2.2  动态共享    446
11.2.3  GOT/PLT表和位置无关代码（PIC）    446
11.2.4  动态加载过程分析    450
第12章  系统调用    457
12.1  概述    457
12.2  系统调用的实现    457
12.2.1  用户实现    459
12.2.2  系统调用表和trap自陷    459
12.2.3  内核实现    469
12.3  各系统调用的实现    469
12.3.1  文件相关调用    471
12.3.2  进程相关调用    491
12.3.3  信号相关调用    538
12.3.4  调试功能调用    558
12.3.5  用户/组ID调用    586
12.3.6  时间相关调用    589
12.3.7  终端相关调用    591
第13章  进程间通信    596
13.1  概述    596
13.2  管道    596
13.2.1  相关系统调用    596
13.2.2  管道实现过程分析    602
13.2.3  应用示例    603
13.2.4  采用内存文件实现管道    608
13.2.5  思考题    610
13.3  文件    610
13.4  有名管道    611
13.5  进程间同步    611
13.5.1  信号量    612
13.5.2  互斥体    621
13.5.3  事件    622
13.6  死锁    634
13.7  其他进程间数据传输方式    636
13.7.1  消息（message）    636
13.7.2  信箱（mailbox）    648
13.7.3  共享内存    671
第14章  多线程的实现    686
14.1  概述    686
14.2  线程和经典进程的比较    686
14.3  线程的示例实现    686
14.3.1  相关数据结构    686
14.3.2  实现方案    689
14.3.3  线程创建调用CreateThread    691
14.3.4  内核改动    695
14.3.5  线程退出调用ExitThread    711
14.3.6  线程id获得调用gettid    712
14.3.7  线程挂起调用SuspendThread    712
14.3.8  线程恢复调用ResumeThread    714
14.3.9  线程终止调用TerminateThread    715
14.3.10  线程ID查询调用GetThreadID    719
14.3.11  线程名查询调用GetThreadName    720
14.3.12  使用示例    721
14.3.13  思考题    723
第15章  网络多用户    724
15.1  系统初始化过程    724
15.1.1  init进程    724
15.1.2  getty程序    725
15.1.3  login程序    725
15.2  telnet程序    730
15.2.1  工作原理    730
15.2.2  常用配置    731
15.3  NFS（网络文件系统）    732
15.3.1  基本原理    733
15.3.2  RPC（远程过程调用）    734
15.3.3  各过程的实现    737
15.3.4  简单示例    741
附录A  参考书目及资源    742
附录B  思考题答案    743