1.1 操作系统的定义 2
1.1.1 计算机系统层次结构图 2
目录 2
第一部分 操作系统初始化 2
第1章 操作系统概述 2
1.1.2 操作系统的定义 3
1.2.1 没有操作系统的第一代计算机 4
1.2 操作系统发展过程中的设计需求分析 4
1.2.2 具有简单批处理操作系统的第二代计算机 5
1.2.3 简单批处理操作系统功能分析 6
1.2.4 多道程序设计的批处理操作系统 7
1.2.6 其他操作系统 8
1.2.5 多道程序设计的分时操作系统 8
1.3.1 大型系统软件分析方法 9
1.3 内核体系结构模型 9
1.3.2 操作系统结构模型 10
1.3.3 UNLX内核系统结构模型 11
1.4 Linux操作系统的出现 12
1.5.1 操作系统运行的全过程 13
1.5 操作系统如何运行一个用户程序 13
1.5.2 客户/服务器工作流程 14
1.5.3 客户/服务器实例 15
1.6.1 重要思想 19
1.6 重要思想和理论 19
1.6.2 重要理论 21
1.7 小结 23
1.9 参考文献 24
1.8 练习题 24
2.1.1 微型计算机基本组成 26
2.1 微型计算机硬件组成 26
第2章 i386硬件与软件接口技术 26
2.1.2 微处理器分类 27
2.1.4 微型计算机总线结构 28
2.1.3 微处理器结构的发展 28
2.2.1 实模式下软件组织 29
2.2 实模式软件结构 29
2.2.3 实模式输入/输出地址空间 31
2.2.2 实模式主存储器地址的产生 31
2.3.1 描述符寄存器 32
2.3 保护模式下存储器管理单元MMU 32
2.3.2 描述符 34
2.3.3 虚拟地址和虚拟地址空间 36
2.3.4 虚实地址转换 37
2.3.5 保护模式指令集 38
2.4.1 多任务与分时系统 39
2.4 保护模式和保护 39
2.4.4 保护性检查 40
2.4.3 保护机制 40
2.4.2 保护环 40
2.4.5 越级访问存储器的代码段和数据段 41
2.5 任务切换机制 43
2.6 小结 44
2.8 参考文献 45
2.7 练习题 45
3.1 BIOS启动过程 46
第3章 Linux系统引导过程 46
3.1.1 i386芯片的启动状态 47
3.1.2 BIOS加载操作系统引导程序 48
3.2.1 软盘引导过程 50
3.2 引导过程 50
3.2.2 硬盘引导过程 53
3.2.3 LILO运行过程分析 55
3.3 实模式下的系统初始化setup()函数 56
3.3.3 准备进入保护模式 57
3.3.2 设置参数 57
3.3.1 setup.S代码签名检查 57
3.3.4 setup.S程序流程图 59
3.3.6 setup.S中全局描述符表分析 63
3.3.5 执行setup.S程序后内存分配图 63
3.4 内核解压缩过程startup_32() 65
3.5 保护模式下的系统初始化startup_32() 67
3.5.2 设置全局描述符表 70
3.5.1 在startup_32中完成临时页表的初始化 70
3.7 练习题 72
3.6 小结 72
3.8 参考文献 73
4.1.1 初始化与体系结构相关的硬件数据结构 74
4.1 初始化系统内核 74
第4章 启动Linux内核 74
4.1.2 解析内核选项 80
4.2 init()函数与init进程 81
4.3.1 继续初始化系统内核 82
4.3 init()函数执行流程 82
4.3.3 init进程 84
4.3.2 系统进程的生成 84
4.4.1 执行脚本文件/etc/rc.d/rc.sysinit 87
4.4 Shell命令文本的执行 87
4.4.2 执行脚本文件/etc/rc.d/rcN.d目录中的各个命令 88
4.5 小结 89
4.4.3 各终端进程的生成 89
4.6 练习题 91
4.7 参考文献 92
5.1.1 多道程序设计与分时共享 94
5.1 并发控制 94
第二部分 并发控制原理及其实现 94
第5章 程序和进程 94
5.1.2 并发控制的硬件支持 95
5.2.1 程序与进程 96
5.2 进程的定义和特征 96
5.2.2 从并发机制理解进程 98
5.3 线程 99
5.2.3 进程的特征 99
5.3.2 内核线程和用户线程 100
5.3.1 多线程 100
5.4 操作系统控制进程的基本方法 101
5.5.1 进程控制块PCB 102
5.5 内核中进程的实现 102
5.5.2 进程状态 104
5.5.3 Linux进程控制块 105
5.5.4 Linux系统O号进程的控制块 107
5.5.5 Linux进程状态 108
5.6 进程的组织 109
5.6.2 pidhash链表 110
5.6.1 进程链表和运行队列链表 110
5.7 内核创建新进程 111
5.6.3 如何寻址当前进程的PCB 111
5.8 Linuxfork的编程实现 112
5.8.1 内核函数do_fork 113
5.8.2 调用fork()的编程实例 117
5.9.1 运行新程序的do_execve() 118
5.9 Linuxexee的编程实现 118
5.8.3 内核怎样运行一个新程序 118
5.9.3 使用fork_exec组合的编程实例 121
5.9.2 二进制处理程序load_binary()完成的工作 121
5.10 从程序到进程 123
5.10.1 文件系统中可执行文件的一般格式 124
5.10.2 shell进程执行用户程序的过程 125
5.12 编程实例——Linux守护进程的编程方法 126
5.11 进程的终止 126
5.12.1 进程组、会话和控制终端 127
5.12.2 Linux守护进程编程细则 129
5.12.3 Linux守护进程实例 131
5.13 小结 132
5.14 练习题 133
5.15 参考文献 134
6.1.1 竞争条件 135
6.1 并发进程控制的基本原理 135
第6章 互斥与同步 135
6.1.2 同步与互斥 136
6.1.3 对互斥操作的要求 137
6.2.1 原子操作 138
6.2 竞争条件产生的原因 138
6.3 基于共享变量的同步操作 139
6.2.2 原子操作的实例 139
6.3.2 锁变量 140
6.3.1 忙等待 140
6.3.3 TestAndSet与Swap指令 141
6.4 信号量 142
6.5.1 DOWN操作 146
6.5 内核使用的P、V操作实例 146
6.5.2 UP操作 149
6.5.5 同步索引节点的信号量 151
6.5.4 同步内存描述符的信号量 151
6.5.3 同步slab高速缓存的信号量 151
6.6.2 关中断 152
6.6.1 内核是不可强占的 152
6.6 内核采用的其他同步技术 152
6.7 等待对列及其操作 153
6.8 小结 155
6.9 练习题 156
6.1 0参考文献 157
7.1.1 可剥夺资源与不可剥夺资源 158
7.1 死锁分析 158
第7章 死锁与饥饿 158
7.1.4 资源分配模型图 159
7.1.3 死锁的条件 159
7.1.2 死锁定义 159
7.3.1 系统资源分配的表示方法 160
7.3 死锁避免 160
7.2 死锁预防 160
7.3.2 系统拒绝启动进程 161
7.3.3 系统拒绝分配资源 162
7.4.1 死锁检测算法 163
7.4 死锁检测和恢复 163
7.4.3 从死锁中恢复 164
7.4.2 死锁检测的时机 164
7.6 饥饿 165
7.5 最简单的死锁策略 165
7.7 小结 166
7.8 练习题 167
7.9 参考文献 168
8.1.1 调度程序的设计目标 169
8.1 进程调度的基本原理 169
第8章 进程调度 169
8.1.2 选择合适的调度策略 170
8.1.3 时间测度指标 171
8.2.1 先来先服务 172
8.2 非强占方式调度算法 172
8.2.2 最短作业优先 173
8.3.1 轮转法 174
8.3 强占式调度算法 174
8.2.3 优先级调度 174
8.3.3 反馈调度算法 175
8.3.2 多级队列 175
8.4.1 在PCB中与调度有关的数据成员 176
8.4 Linux进程调度的实现 176
8.4.2 Linux调度策略 177
8.4.3 Linux调度函数schedule() 179
8.4.4 Linux调度机制 183
8.5 调度程序的编程实例 185
8.6 小结 187
8.7 练习题 188
8.8 参考文献 189
9.1.1 Intel80386芯片的中断接口 190
9.1 基于IBMPC机的中断接口电路 190
第9章 中断技术 190
9.1.2 使用82C59芯片连结外围设备的中断接口电路 191
9.2.1 异常 193
9.2 中断和异常 193
9.2.2 中断和异常的优先级 195
9.3.1 中断和异常向量 196
9.3 中断向量表和中断描述符表 196
9.4 Linux中断系统的初始化过程 197
9.3.2 中断门和陷阱门的区别 197
9.4.2 第二次初始化中断描述符表 198
9.4.1 第一次初始化中断描述符表 198
9.5.1 异常处理过程 200
9.5 异常处理 200
9.5.2 异常处理程序 201
9.6.1 硬件设备使用的中断向量 202
9.6 中断处理 202
9.5.3 内核管理硬件资源的两种异常 202
9.6.2 中断处理使用的数据结构 203
9.6.3 中断系统初始化函数init_IRQ 205
9.6.4 中断处理程序的执行过程 206
9.6.6 执行所有的中断服务例程 208
9.6.5 保存断点现场 208
9.6.7 内核模式的设备驱动程序 209
9.7 下半部分 210
9.7.1 Linux对下半部分的组织 211
9.7.2 执行do_bottom_half()函数 212
9.8 动态安装和释放中断处理程序 213
9.7.3 调度do_bottom_half()函数运行的时机 213
9.9 从中断和异常返回 215
9.10 一个中断处理实例 218
9.10.2 定时器中断的下半部 219
9.10.1 定时器中断的上半部 219
9.10.3 预定义的任务队列 220
9.11 小结 222
9.12 练习题 223
9.13 参考文献 224
10.1 标准C函数库和系统调用 225
第10章 系统调用接口 225
10.2.1 陷阱门处理的模式转换 226
10.2 模式转换的硬件处理 226
10.2.2 调用门处理的模式转换 227
10.3.1 内核对系统调用的初始化 229
10.3 系统调用接口 229
10.3.2 系统调用的执行流程 230
10.3.3 封装例程 231
10.3.4 系统调用号与系统调用表 232
10.3.5 system_call的执行过程 233
10.4 lcall7的执行过程 234
10.5 内核中添加新系统调用的实例 235
10.6 小结 238
10.8 参考文献 239
10.7 练习题 239
11.1 存储器功能需求分析 242
第11章 存储器管理及Linux实现 242
第三部分 OS资源管理及其实现 242
11.1.3 共享 243
11.1.2 保护 243
11.1.1 重定位 243
11.3 内存管理 244
11.2.2 物理组织 244
11.2 存储器的组织方式 244
11.2.1 逻辑组织 244
11.3.1 固定分区 245
11.3.2 动态分区 246
11.4 位图 247
11.5 伙伴系统 248
11.6.2 固定分区使用的重定位技术 250
11.6.1 存储器管理使用的地址类型 250
11.6 重定位技术 250
11.6.3 分页使用的重定位技术 251
11.6.4 分段使用的重定位技术 252
11.7 虚拟存储器管理技术 253
11.7.2 虚拟存储器管理软件 254
11.7.1 局部性原理 254
11.7.3 交换区 256
11.8 通用存储器管理模型 256
11.9 Linux在i386中的分段和分页 257
11.9.1 Linux使用的分段 258
11.9.2 Linux使用的分页 260
11.9.3 Linux在i386平台上定义的页表项格式 261
11.10 Linux内存管理 262
11.10.1 描述内存页框的page数据结构 263
11.10.2 基于buddy算法的内存页框管理 264
11.11 基于slab算法的内存区管理 266
11.11.1 slab分配器的组成 267
11.11.2 slab分配器与页框级分配器的接口和实现 269
11.11.3 连续内存区的分配和释放函数 270
11.12.1 描述非连续内存区的数据结构 271
11.12 非连续内存区的分配和释放 271
11.12.2 分配和释放非连续内存区的函数 272
11.13.1 structmm_struct和structvm_area_struct结构 274
11.13 进程的地址空间 274
11.13.2 进程地址空间的存取权限 276
11.13.3 对线性区进行处理的底层函数 277
11.13.4 进程线性地址空间的映射do_mmap() 279
11.14.1 缺页异常处理程序do_page_fault() 281
11.14 页面失效处理 281
11.13.5 释放进程线性地址空间do_munmap() 281
11.14.2 请求调页 286
11.14.4 调用sys_brk动态增长内存 288
11.14.3 写时拷贝 288
11.15 交换 289
11.15.1 描述交换空间的数据结构 290
11.15.2 页面替换策略 291
11.16.1 页交换守护进程kswapd 292
11.16 页换出操作 292
11.16.2 kswapd()的执行流程 293
11.16.3 页换入do_swap_page() 294
11.16.4 页换出 295
11.18 小结 297
11.17 对交换区数据结构进行操作的函数 297
11.19 练习题 299
11.20 参考文献 300
12.1.2 磁盘的逻辑组织 302
12.1.1 磁盘结构 302
第12章 文件管理及Linux实现 302
12.1 磁盘的物理组织与调度 302
12.1.3 磁盘性能参数 303
12.1.4 磁盘调度算法 304
12.2.1 文件管理的设计目标 305
12.2 文件管理需求分析 305
12.1.5 磁盘纠错 305
12.2.2 文件管理系统结构模型 306
12.3.3 文件属性 307
12.3.2 文件类型和存取方式 307
12.3 文件 307
12.3.1 文件结构 307
12.4.1 目录结构 308
12.4 目录 308
12.5 文件系统的组织 309
12.4.3 目录操作 309
12.4.2 路径名 309
12.5.2 目录表表项的格式 310
12.5.1 文件组织 310
12.5.5 文件系统的一致性 311
12.5.4 磁盘空间管理 311
12.5.3 共享文件 311
12.6 文件系统的保护机制 312
12.7.1 虚拟文件系统的设计思路 313
12.7 虚拟文件系统VFS 313
12.7.2 虚拟文件系统VFS框架 314
12.8.1 VFS超级块数据结构 315
12.8 Linux虚拟文件系统的数据结构 315
12.8.2 VFS的目录项数据结构 317
12.8.3 VFS的inode节点数据结构 319
12.8.4 VFS中数据结构之间的关系 321
12.9.1 文件系统注册链表 322
12.9 对虚拟文件系统的管理 322
12.9.3 根文件系统的安装 323
12.9.2 文件系统安装注册链表 323
12.10.1 安装一个文件系统sys_mount() 325
12.10 对文件系统模块的安装和卸载 325
12.11 进程与文件系统的联系 326
12.10.2 卸载一个文件系统sys_umount() 326
12.11.1 文件对象 327
12.11.2 用户打开文件表 328
12.11.3 根目录和当前工作目录 329
12.12 文件加锁 331
12.13 磁盘数据的内存高速缓冲区 332
12.13.1 缓冲区高速缓存的数据结构 333
12.13.2 buffercache的组织 335
12.13.3 对buffercache的基本操作 337
12.13.4 把脏缓冲区写入磁盘 338
12.14 EXT2文件系统 339
12.14.2 EXT2减少碎片的方案 340
12.14.1 EXT2对物理磁盘的组织 340
12.15 EXT2磁盘重要数据结构 341
12.14.3 EXT2对磁盘块的分配原则 341
12.15.1 EXT2的目录项数据结构 342
12.5.2 EXT2的磁盘i节点结构 343
12.15.3 EXT2磁盘上的超级块 346
12.15.5 EXT2的块位图和索引节点位图 347
12.15.4 EXT2的组描述符 347
12.16.1 EXT2的内存超级块 348
12.16 EXT2的内核组织 348
12.15.6 EXT2存放文件的数据块 348
12.16.3 磁盘i节点读入高速缓存的过程 350
12.16.2 EXT2的内存i节点 350
12.17 如何通过路径名找到索引节点 352
12.18.2 EXT2文件系统的不足 354
12.18.1 关于日志式文件系统 354
12.18 EXT3文件系统 354
12.18.3 日志文件系统的工作原理 355
12.18.4 EXT3日志文件系统的具体实现 356
12.19 小结 357
12.18.5 EXT3文件系统的额外开销 357
12.20 练习题 358
12.21 参考文献 359
13.1.2 内核对设备的分类 360
13.1.1 I/O设备的分类 360
第13章 I/O设备管理与设备驱动程序 360
13.1 I/O系统的基本组成 360
13.1.3 I/O接口功能 361
13.1.4 CPU与I/O设备交互的控制方式 362
13.2 I/O系统管理软件的设计原理 363
13.4.1 设备命名方法 364
13.4 逻辑I/O管理 364
13.3 用户程序 364
13.4.3 为设备分配和释放缓冲区 366
13.4.2 访问设备的权限和设备保护 366
13.5 设备驱动程序和中断控制层 367
13.6 设备驱动程序的组织实例 368
13.6.1 设备驱动程序的工作原理 369
13.6.2 逻辑I/O与设备驱动程序接口 370
13.6.3 系统调用与驱动程序接口 373
13.7 设备驱动程序模块 374
13.6.4 安装中断处理程序 374
13.7.2 可动态加载和卸载的设备驱动程序模块 375
13.7.1 静态链接的设备驱动程序模块 375
13.8 了解系统基本配置 376
13.7.3 用户空间的设备驱动程序 376
13.8.2 内核中驱动程序清单 377
13.8.1 I/O端口 377
13.9 设备驱动程序中使用的内核函数 378
13.8.3 内核的中断报告显示 378
13.9.2 分配和释放内存的函数 379
13.9.1 操作I/O端口的函数 379
13.9.4 同步和计时要使用的内核函数 380
13.9.3 访问设备卡上内存的函数 380
13.9.5 中断管理内核函数 381
13.10.1 设备驱动程序与内核 383
13.10 编制设备驱动程序的基本方法 383
13.9.6 注册和注销设备的内核函数 383
13.9.7 其他内核函数 383
13.10.3 驱动程序与引导 388
13.10.2 驱动程序与硬件 388
13.11.1 编程用到的硬件 389
13.11 内核级设备驱动程序编程实例 389
13.11.2 上半部与下半部各自的功能 390
13.11.3 内核驱动程序的上半部编程 391
13.11.4 内核驱动程序的下半部编程 395
13.11.5 模块的安装与卸载 398
13.11.6 访问设备驱动程序的用户程序 399
13.11.7 编译设备驱动程序 400
13.12 小结 401
13.11.8 使用内核设备驱动程序模块 401
13.13 练习题 402
13.14 参考文献 403
14.2 信号机制 406
14.1 进程间通信的设计目标 406
第四部分 IPC和网络编程接口 406
第14章 最早的IPC方法:信号与管道 406
14.2.2 信号的产生与处理 407
14.2.1 什么是信号 407
14.3 发送信号 409
14.3.1 信号操作用到的数据结构 410
14.3.2 数据结构sigset_t上的一组简单操作函数 411
14.3.3 传送信号 412
14.4 接收信号 414
14.4.2 忽略信号 415
14.4.1 分析do_signal()函数 415
14.4.4 捕获一个信号 416
14.4.3 执行一个默认操作 416
14.5 捕获一个信号的编程实例 418
14.4.7 被中断的系统调用获得重新执行 418
14.4.5 执行信号处理程序 418
14.4.6 终止信号处理程序 418
14.6 管道 420
14.6.2 do_pipe()——创建一个管道 421
14.6.1 structpipe_inode_info数据结构 421
14.6.3 读管道 422
14.6.4 写管道 423
14.7 无名管道的编程实例 424
14.6.5 撤销管道 424
14.8.2 打开FIFO 425
14.8.1 创建一个FTFO 425
14.8 有名管道FIFO 425
14.9 编写有名管道的实用程序 426
14.8.3 读写FlFO 426
14.10 小结 427
14.12 参考文献 428
14.11 练习题 428
15.1.2 控制IPC资源的系统调用 429
15.1.1 创建IPC资源的系统调用 429
第15章 SystemV进程间通信 429
15.1 与IPC相关的系统调用 429
15.2 IPC资源中的公共元素及属性 430
15.1.4 IPC系统调用在i386体系结构中的实现 430
15.1.3 操作IPC资源的系统调用 430
15.3.1 与信号量操作相关的数据结构 432
15.3 IPC信号量 432
15.3.2 sys_semop()函数的功能 435
15.4 IPC信号量的编程示例 436
15.3.3 sys_semctl()函数的功能 436
15.6 IPC消息队列 438
15.5 信号量小结 438
15.6.1 与消息队列操作相关的数据结构 439
15.6.2 发送一个消息 440
15.6.3 接收消息和释放消息队列 441
15.7 IPC消息队列的编程示例 442
15.9.1 IPC共享内存的数据结构 443
15.9 共享内存 443
15.8 消息队列小结 443
15.9.2 连接IPC共享内存 445
15.9.4 剥离和释放IPC共享内存段 446
15.9.3 IPC共享内存请求调页的过程 446
15.10 IPC共享内存编程示例 447
15.12 练习题 451
15.11 小结 451
15.13 参考文献 452
16.1.1 OSI模型和网际协议族 453
16.1 Linux网络系统分层结构 453
第16章 Linux网络接口及内核实现 453
16.1.2 Linux网络协议族分层结构 454
16.2.1 传输控制协议——TCP 455
16.2 TCP和UDp 455
16.3.1 套接口地址结构 456
16.3 内核中与发送/接收相关的数据结构 456
16.2.2 用户数据报协议——UDP 456
16.3.2 数据包结构 457
16.3.3 建立网络连接的数据结构 461
16.3.4 协议操作函数使用的数据结构 464
16.4 网络连接的建立和关闭 465
16.4.1 网络连接的建立 466
16.4.2 关闭网络连接 470
16.5 发送数据 471
16.5.1 发送数据的系统调用接口 472
16.5.2 从INET协议层到IP层 473
16.5.3 IP层到硬件层的数据发送过程 474
16.5.4 硬件层的数据发送过程 475
16.6.1 接收数据的系统调用接口 476
16.6 接收数据 476
16.6.2 硬件层接收数据分析 477
16.6.3 从IP层接收数据 478
16.6.4 从INET层接收数据 479
16.7 小结 480
16.9 参考文献 481
16.8 练习题 481
17.1.1 socket()函数 482
17.1 套接口函数 482
第17章 TCP套接口编程的基本方法 482
17.1.2 其他套接口函数 483
17.2.1 建立TCF连接的过程 485
17.2 TCP连接的建立和终止过程 485
17.2.2 终止TCP连接的过程 486
17.3.2 TCP客户程序的实现 487
17.3.1 TCP客户程序设计方法 487
17.3 编制TCP客户程序 487
17.4.2 一个简单TCF服务器的实现 489
17.4.1 一个简单TCP服务器的编程方法 489
17.4 编制TCP服务器程序 489
17.4.3 TCP并发服务器的实现 491
17.7 参考文献 493
17.6 练习题 493
17.5 小结 493
18.1 UDP程序使用的套接口函数 494
第18章 UDP套接口编程的基本方法 494
18.2 发送UDP数据报的编程实例 495
18.3 接收UDP数据报的编程实例 496
18.5 练习题 498
18.4 小结 498
18.6 参考文献 499
附录 Linux源代码目录结构与内容 500