Linux内核设计的艺术
出版信息
新设计团队 / 机械工业出版社华章公司 / 2011-6-20 / 79.00元
内容简介
关于Linux内核的书已经不计其数,但这本书却是独树一帜的,它的内容代表着Linux内核研究成果的世界顶尖级水平,它在世界范围内首次提出并阐述了操作系统设计的核心指导思想——主奴机制,这是所有操作系统研究者的一笔宝贵财富。本书可能也代表着同类图书的顶尖水平,是一本真正能引导我们较为容易地、极为透彻地理解Linux内核的经典之作,也可能是当前唯一能从本质上指引我们去设计和开发拥有自主知识产权的操作系统的著作。它的出版也许会成为Linux内核研究领域的一个里程碑事件。
本书的最大特点是它的写作方式和内容组织方式,与同类书完全不同。它在深刻地分析了传统讲解方法的利弊之后,破旧立新,从认知学的角度开创了一种全新的方式。以操作系统的真实运行过程为主线,结合真实的内核源代码、349幅精确的内核运行时序图和具有点睛之妙的文字说明,对操作系统从开机加电到系统完全准备就绪的整个过程进行了系统而完整地分析,深刻地揭示了其间每一个动作的设计意图和实现原理,完美地再现了操作系统设计者的设计思路。阅读本书就如同跟随着操作系统设计者一起去思考,我们会在阅读的过程中发现Linux内核设计的精妙,会发现原来处处都“暗藏玄机”,哪怕是一行很短的代码。
本书在所有细节上都力求完美。为了保证知识的准确性,操作系统运行过程中的每个动作都经过了严格的考证;为了让我们真正理解Linux内核的原理,它突破传统,以Linux的真实运行过程为主线进行讲解;为了做到真正易于理解,创新性地使用了图解的方式,精心绘制了349幅分辨率600dpi的时序图,图中表现的运行时结构和状态与操作系统实际运行时的真实状态完全吻合;为了提高阅读体验,本书采用了双色印刷,以便于我们更清楚地观察每一幅图中的细节。
作者简介
暂无
目录
本书导读
前言
第1章 从开机加电到执行main函数之前的过程1
1.1 启动BIOS,准备实模式下的中断向量表和中断服务程序1
1.1.1 BIOS的启动原理2
1.1.2 BIOS在内存中加载中断向量表和中断服务程序3
1.2 加载操作系统内核程序并为保护模式做准备4
1.2.1 加载第一部分代码—引导程序(bootsect)5
1.2.2 加载第二部分代码—setup7
1.2.3 加载第三部分代码—system模块12
1.3 开始向32位模式转变,为main函数的调用做准备16
1.3.1 关中断并将system移动到内存地址起始位置0x0000016
1.3.2 设置中断描述符表和全局描述符表18
1.3.3 打开A20,实现32位寻址20
1.3.4 为在保护模式下执行head.s做准备21
1.3.5 head.s开始执行24
1.4 本章小结41
第2章 从main到怠速42
2.1 开中断之前的准备工作43
2.1.1 复制根设备号和硬盘参数表 44
2.1.2 物理内存规划格局45
2.1.3 虚拟盘设置与初始化46
2.1.4 内存管理结构mem_map初始化47
2.1.5 异常处理类中断服务程序挂接48
2.1.6 初始化块设备请求项结构50
2.1.7 与建立人机交互界面相关的外设的中断服务程序挂接52
2.1.8 开机启动时间设置55
2.1.9 系统开始激活进程056
2.1.10 进程相关事务初始化设置57
2.1.11 时钟中断设置59
2.1.12 系统调用服务程序挂接59
2.1.13 初始化缓冲区管理结构61
2.1.14 初始化硬盘63
2.1.15 初始化软盘65
2.1.16 开中断66
2.2 进程创建的最基本动作67
2.2.1 操作系统为进程0创建进程1做准备67
2.2.2 在进程槽中为进程1 申请一个空闲位置并获取进程号71
2.2.3 复制进程信息之前,先将一些数据压栈73
2.2.4 初步设置进程1管理结构74
2.2.5 进程0创建进程1的过程中发生时钟中断76
2.2.6 从时钟中断返回78
2.2.7 调整进程1管理结构79
2.2.8 设置进程1的线性地址空间及物理页面81
2.2.9 继续调整进程1管理结构84
2.2.10 操作系统如何区分进程0和进程187
2.2.11 进程0准备切换到进程189
2.2.12 系统切换到进程1执行90
2.3 加载根文件系统92
2.3.1 进程1如何开始执行96
2.3.2 进程1开始执行98
2.3.3 进程1开始以数据块的形式操作硬盘99
2.3.4 将找到的缓冲块与请求项挂接101
2.3.5 将请求项与硬盘处理函数挂接104
2.3.6 进行硬盘读盘前的准备工作105
2.3.7 给硬盘下达读盘指令106
2.3.8 进程1由于等待读盘操作挂起107
2.3.9 系统切换到进程0执行109
2.3.10 进程0的执行过程110
2.3.11 进程0执行过程中发生硬盘中断111
2.3.12 硬盘中断服务程序响应后,进程0继续执行113
2.3.13 再次响应硬盘中断并唤醒进程1114
2.3.14 读盘操作完成后,进程1继续执行116
2.3.15 进程1继续设置硬盘管理结构117
2.3.16 进程1获取软盘超级块,为加载根文件系统做准备118
2.3.17 进程1备份超级块数据119
2.3.18 进程1将根文件系统从软盘拷贝到虚拟盘120
2.3.19 进程1开始加载根文件系统122
2.3.20 进程1准备加载根文件系统超级块123
2.3.21 进程1加载根文件系统超级块124
2.3.22 进程1继续加载根文件系统126
2.3.23 进程1准备读取根目录i节点127
2.3.24 进程1加载根目录i节点128
2.3.25 进程1结束加载根文件系统的过程129
2.4 打开终端设备文件及复制文件句柄131
2.4.1 进程1与内核文件表挂接,为打开文件做准备133
2.4.2 确定打开操作的起点135
2.4.3 获得枝梢i节点—dev目录文件的i节点136
2.4.4 确定dev目录文件i节点为枝梢i节点137
2.4.5 继续返回枝梢i节点138
2.4.6 查找tty0文件的i节点138
2.4.7 将tty0设备文件的i节点返回给sys_open系统调用 139
2.4.8 分析tty0文件i节点140
2.4.9 设置文件管理结构并返回给用户进程141
2.4.10 进程1复制tty0文件句柄142
2.4.11 进程1继续复制tty0文件句柄144
2.5 创建进程2145
2.5.1 进程1准备创建进程2145
2.5.2 复制进程2管理结构并进行调整146
2.5.3 设置进程2的页目录项并复制进程2的页表146
2.5.4 调整进程2管理结构中与文件有关的内容146
2.5.5 进程1执行过程中发生时钟中断148
2.5.6 进程1从时钟中断返回,准备切换到进程2150
2.6 进程1等待进程2退出150
2.6.1 进程1查找它自己的子进程151
2.6.2 对进程2的状态进行处理151
2.6.3 切换到进程2执行153
2.7 shell程序的加载154
2.7.1 进程2开始执行156
2.7.2 为打开/etc/rc文件做准备156
2.7.3 进程2打开“/etc/rc”配置文件157
2.7.4 通过压栈为加载shell文件做准备158
2.7.5 为参数和环境变量设置做准备159
2.7.6 得到shell文件的i节点160
2.7.7 为加载参数和环境变量做准备161
2.7.8 根据i节点,对shell文件进行检测162
2.7.9 检测shell文件头163
2.7.10 备份文件头并进行分析163
2.7.11 对shell文件进行进一步分析165
2.7.12 拷贝参数和环境变量166
2.7.13 调整进程2的管理结构167
2.7.14 继续调整进程2管理结构168
2.7.15 释放进程2继承的页面169
2.7.16 检测协处理器170
2.7.17 调整shell程序所在的线性空间地址171
2.7.18 为shell程序准备参数和环境变量172
2.7.19 继续调整进程2管理结构173
2.7.20 调整EIP,使其指向shell程序入口地址173
2.7.21 shell程序执行引发缺页中断175
2.7.22 缺页中断中shell程序加载前的检测175
2.7.23 为即将载入的内容申请页面177
2.7.24 将shell程序载入新获得的页面177
2.7.25 根据shell程序的情况,调整页面的内容178
2.7.26 将线性地址空间与程序所在的物理页面对应179
2.8 系统实现怠速180
2.8.1 shell进程准备创建update进程180
2.8.2 进程2开始执行/etc/rc文件181
2.8.3 准备加载update进程181
2.8.4 update进程的作用182
2.8.5 shell程序检测“/etc/rc”文件183
2.8.6 shell进程退出184
2.8.7 shell进程退出善后处理185
2.8.8 进程1清理shell进程管理结构187
2.8.9 系统开始重建shell190
2.8.10 shell进程为何不会再次退出192
2.9 小结194
第3章 安装文件系统195
3.1 获取硬盘设备号196
3.1.1 用户发出安装硬盘文件系统指令196
3.1.2 从分析路径开始,准备查找hd1设备的挂接点197
3.1.3 以根目录i节点为依托,得到dev目录文件的i节点197
3.1.4 从dev目录文件中找到代表hd1设备文件的目录项198
3.1.5 得到hd1设备文件的i节点号199
3.1.6 释放dev目录文件的相关内容200
3.1.7 得到hd1设备文件的i节点200
3.1.8 获得hd1设备的设备号200
3.1.9 释放hd1设备文件的i节点201
3.2 获取虚拟盘上的挂接点202
3.3 得到hd1设备文件的超级块202
3.3.1 准备读取hd1设备文件超级块203
3.3.2 为hd1设备文件的超级块找到存储位置203
3.3.3 初始化空闲超级块并加锁203
3.3.4 从硬盘获得hd1设备文件的超级块204
3.3.5 加载逻辑块位图和i节点位图205
3.4 将hd1设备文件与mnt目录文件的i节点挂接206
3.5 小结207
第4章 文件操作208
4.1 打开文件211
4.1.1 用户程序调用open库函数产生软中断212
4.1.2 建立用户进程与文件管理表的关系213
4.1.3 从硬盘上获取helloc.txt文件的i节点214
4.1.4 将helloc.txt文件与文件管理表相挂接226
4.2 读文件227
4.2.1 为按照用户要求读入文件做准备228
4.2.2 确定要读入的数据块的位置230
4.2.3 将指定的数据块从硬盘读入到高速缓冲块233
4.2.4 将数据拷贝到用户指定的内存234
4.3 新建文件237
4.3.1 查找路径“/mnt/user/hello.txt”238
4.3.2 为hello.txt文件新建一个i节点240
4.3.3 为hello.txt文件新建目录项242
4.3.4 完成hello.txt新建操作并返回给用户进程245
4.4 写文件246
4.4.1 文件写入前的准备工作248
4.4.2 确定hello.txt文件的写入位置249
4.4.3 为数据的写入申请缓冲块252
4.4.4 将指定的写入数据从用户数据区拷贝到缓冲块253
4.4.5 数据同步到硬盘的方法1255
4.4.6 将文件写入硬盘的情况2257
4.5 修改文件260
4.5.1 对文件的当前操作指针进行重定位261
4.5.2 对文件进行修改261
4.6 关闭文件263
4.6.1 当前进程与文件管理表“脱钩”264
4.6.2 将文件管理表中hello.txt对应的引用次数减1265
4.6.3 hello.txt文件与文件管理表“脱钩”266
4.7 删除文件268
4.7.1 系统准备删除hello.txt文件268
4.7.2 删除hello.txt文件在硬盘上对应的数据和i节点270
4.7.3 对hello.txt文件所在的user目录做处理275
4.8 本章小结275
第5章 用户进程与内存管理277
5.1 用户进程的创建277
5.1.1 为创建进程str1准备条件277
5.1.2 为str1进程管理结构找到存储空间279
5.1.3 复制str1进程管理结构281
5.1.4 确定str1进程在线性空间中的位置282
5.1.5 复制str1进程页表并设置其对应的页目录项283
5.1.6 调整str1进程中与文件相关的结构285
5.1.7 建立str1进程与全局描述符表GDT的关联286
5.1.8 将str1进程设为就绪态287
5.2 为用户进程str1的加载做准备288
5.2.1 为str1进程加载自身对应的程序做准备288
5.2.2 读取str1可执行文件的i节点并统计参数和环境变量289
5.2.3 读取str1可执行文件的文件头290
5.2.4 对str1可执行程序文件头进行分析291
5.2.5 拷贝str1可执行程序的参数和环境变量292
5.2.6 调整str1进程管理结构中可执行程序对应的i节点292
5.2.7 继续调整str1进程管理结构—文件和信号相关的字段293
5.2.8 释放str1进程的页表294
5.2.9 重新设置str1的程序代码段和数据段295
5.2.10 创建环境变量和参数指针表296
5.2.11 继续根据str1可执行程序情况调整str1进程管理结构297
5.2.12 设置str1可执行程序的栈指针和eip值297
5.3 对缺页中断的处理298
5.3.1 产生缺页中断并由操作系统响应298
5.3.2 为str1程序申请一个内存页面299
5.3.3 将str1程序加载到新分配的页面中300
5.3.4 检测是否需要对页面剩余空间清0300
5.3.5 将str1程序占用的物理内存地址与str1进程的线性地址空间对应301
5.3.6 不断通过缺页中断加载str1程序的全部内容301
5.3.7 str1程序需要压栈302
5.3.8 str1程序第一次调用foo程序压栈302
5.3.9 str1程序第二次压栈,产生缺页中断302
5.3.10 处理str1程序第二次压栈产生的缺页中断302
5.3.11 str1程序继续执行,反复压栈并产生缺页中断303
5.3.12 str1程序运行结束后清栈303
5.4 str1用户进程的退出305
5.4.1 str1进程准备退出305
5.4.2 释放str1程序所占页面305
5.4.3 解除str1程序与文件有关的内容并给父进程发信号306
5.4.4 str1程序退出后执行进程调度307
5.5 多个用户进程“同时”运行308
5.5.1 依次创建str1、str2和str3进程308
5.5.2 str1进程压栈的执行效果309
5.5.3 str1运行过程中产生时钟中断并切换到str2执行309
5.5.4 str2执行过程遇到时钟中断切换到str3执行310
5.5.5 三个程序执行一段时间后在主内存的分布格局311
5.6 进程的调度与切换311
5.6.1 str1刚被shell创建并处于就绪态311
5.6.2 shell进程将自己挂起,然后准备切换到str1执行311
5.6.3 准备切换到str1进程执行312
5.6.4 str1执行时发生时钟中断314
5.6.5 时钟中断递减str1运行的时间片315
5.6.6 str1执行一段时间后挂起,shell进程新建str2进程315
5.6.7 str2运行期间发生时钟中断316
5.6.8 系统切换到str1程序执行317
5.7 内核的分页318
5.7.1 为设置内核的页目录表和页表做准备—所占空间清0318
5.7.2 设置内核对应的页目录项和页表项的内容319
5.7.3 设置内核对应的全局描述符表GDT320
5.8 页写保护321
5.8.1 进程A和进程B共享页面321
5.8.2 进程A准备进行压栈操作322
5.8.3 进程A的压栈动作引发页写保护322
5.8.4 将进程A的页表指向新申请的页面323
5.8.5 拷贝原页面内容到进程A新申请的页面324
5.8.6 进程B准备操作共享页面325
5.8.7 假设进程B先执行压栈操作的情况325
5.9 小结326
第6章 多个进程“同时”操作一个文件327
6.1 三个进程操作同一个文件327
6.1.1 进程A执行,hello.txt文件被打开328
6.1.2 进程A读取hello.txt文件并由于等待硬盘中断而被系统挂起328
6.1.3 进程B准备打开hello.txt文件330
6.1.4 系统准备为进程B获取hello.txt文件的i节点332
6.1.5 系统找到hello.txt文件已经载入的i节点333
6.1.6 系统准备为进程B从硬盘上读取hello.txt文件334
6.1.7 系统找到了正在操作的缓冲块,将进程B挂起335
6.1.8 系统再次切换到进程0执行337
6.1.9 进程C启动并打开hello.txt文件337
6.1.10 进程C也由于等待缓冲块解锁而被系统挂起338
6.1.11 缓冲块解锁后先唤醒进程C339
6.1.12 系统将进程B设为就绪状态340
6.1.13 系统将指定数据写入缓冲块341
6.1.14 写入完成后,进程C继续执行341
6.1.15 进程C准备切换到进程B342
6.1.16 进程C切换到进程B执行,进程B唤醒进程A342
6.1.17 进程B不断执行,直到时间片减为0后切换到进程A执行343
6.1.18 进程A、B、C退出,写入数据由update进程同步344
6.2 缓冲区与外设的数据同步344
6.2.1 系统不断为进程A向缓冲区写入数据346
6.2.2 继续执行引发缓冲块数据需要同步346
6.2.3 将缓冲区中的数据同步到硬盘上347
6.2.4 进程A由于等待空闲请求项而被系统挂起349
6.2.5 进程B开始执行350
6.2.6 进程B也被挂起351
6.2.7 进程C开始执行并随后被挂起352
6.2.8 进程A和进程C均被唤醒352
6.2.9 进程B切换到进程A执行354
6.3 小结356
第7章 IPC问题358
7.1 管道机制358
7.1.1 为管道文件在文件管理表中申请空闲项360
7.1.2 为管道文件与进程建立联系创造条件360
7.1.3 创建管道文件i节点361
7.1.4 将管道文件i节点与文件管理表建立联系362
7.1.5 将管道文件句柄返回给用户进程363
7.1.6 读管道进程开始操作管道文件363
7.1.7 写管道进程向管道中写入数据364
7.1.8 写管道进程继续向管道写入数据366
7.1.9 写管道进程已将管道空间写满366
7.1.10 写管道进程挂起366
7.1.11 读管道进程从管道中读出数据367
7.1.12 读管道进程继续执行,不断从管道中读出数据369
7.1.13 读管道进程执行中发生时钟中断369
7.1.14 读管道进程执行过程中再次发生时钟中断370
7.1.15 读管道进程切换到写管道进程执行371
7.1.16 写管道进程挂起切换到读管道进程执行371
7.1.17 读管道进程继续执行,直到把管道中的数据读完372
7.1.18 读取完成后,读进程挂起,写进程继续执行373
7.2 信号机制374
7.2.1 processig进程开始执行376
7.2.2 processig进程进入可中断等待状态377
7.2.3 sendsig进程开始执行并向processig进程发信号379
7.2.4 系统检测当前进程接收到信号并准备处理381
7.2.5 系统检测信号处理函数指针挂接是否正常382
7.2.6 调整processig进程的内核栈结构,使之先执行信号处理函数383
7.2.7 信号对进程执行状态的影响386
7.3 小结393
第8章 操作系统的设计指导思想395
8.1 运行一个最简单的程序,看操作系统为程序运行做了哪些工作395
8.2 操作系统的设计指导思想—主奴机制398
8.2.1 主奴机制中的进程及进程创建机制399
8.2.2 操作系统在内存管理中的主奴机制400
8.2.3 操作系统在文件系统中体现的主奴机制401
8.3 实现主奴机制的三种关键技术402
8.3.1 保护和分页402
8.3.2 特权级405
8.3.3 中断405
8.4 建立主奴机制的决定性因素—先机407
8.5 软件和硬件的关系:主机与进程、外设与文件408
8.5.1 非用户进程—进程0、进程1、shell进程408
8.5.2 文件与数据存储409
8.6 父子进程共享页面414
8.7 操作系统的全局中断与进程的局部中断—信号414
8.8 小结415
结束语415
“新设计团队”简介416
附录 搭建Linux 0.11系统环境421