这书应用场景Linux2.6.34核心详解了Linux核心系统软件,遮盖了从关键核心系统软件的运用到核心设计构思与保持等各层面的內容。这书主题思想包含:进程管理、进程调度、自我管理和定时器、系统调用插口、运行内存寻址方式、内存管理和页缓存文件、VFS、核心同歩及其调节技术性等。一起这书也包含了Linux2.6核心中极具特点的內容,包含CFS生产调度程序流程、占领式核心、块I/O层及其I/O生产调度程序流程等。这书选用理论研究紧密结合的线路,可以领着用户迅速走入Linux核心全球,真实开发设计核心编码。
目录
- 译者序
- 序言
- 前言
- 作者简介
- 第1章 Linux内核简介1
- 1.1 Unix的历史1
- 1.2 追寻Linus足迹:Linux简介2
- 1.3 操作系统和内核简介3
- 1.4 Linux内核和传统Unix内核的比较5
- 1.5 Linux内核版本7
- 1.6 Linux内核开发者社区8
- 1.7 小结8
- 第2章 从内核出发10
- 2.1 获取内核源码10
- 2.1.1 使用Git10
- 2.1.1 安装内核源代码10
- 2.1.3 使用补丁11
- 2.2 内核源码树11
- 2.3 编译内核12
- 2.3.1 配置内核12
- 2.3.2 减少编译的垃圾信息14
- 2.3.3 衍生多个编译作业?14
- 2.3.4 安装新内核14
- 2.4 内核开发的特点15
- 2.4.1 无libc库抑或无标准头文件15
- 2.4.2 GNU?C16
- 2.4.3 没有内存保护机制18
- 2.4.4 不要轻易在内核中使用浮点数18
- 2.4.5 容积小而固定的栈18
- 2.4.6 同步和并发18
- 2.4.7 可移植性的重要性19
- 2.5 小结19
- 第3章 进程管理20
- 3.1 进程20
- 3.2 进程描述符及任务结构?21
- 3.2.1 分配进程描述符22
- 3.2.2 进程描述符的存放23
- 3.2.3 进程状态23
- 3.2.4 设置当前进程状态25
- 3.2.5 进程上下文25
- 3.2.6 进程家族树25
- 3.3 进程创建26
- 3.3.1 写时拷贝27
- 3.3.2 fork()27
- 3.3.3 vfork()28
- 3.4 线程在Linux中的实现28
- 3.4.1 创建线程29
- 3.4.2 内核线程30
- 3.5 进程终结31
- 3.5.1 删除进程描述符32
- 3.5.2 孤儿进程造成的进退维谷32
- 3.6 小结34
- 第4章 进程调度35
- 4.1 多任务35
- 4.2 Linux?的进程调度36
- 4.3 策略36
- 4.3.1 I/O消耗型和处理器消耗型的进程36
- 4.3.2 进程优先级37
- 4.3.3 时间片38
- 4.3.4 调度策略的活动38
- 4.4 Linux调度算法39
- 4.4.1 调度器类39
- 4.4.2 Unix?系统中的进程调度40
- 4.4.3 公平调度41
- 4.5 Linux调度的实现42
- 4.5.1 时间记账42
- 4.5.2 进程选择44
- 4.5.3 调度器入口48
- 4.5.4 睡眠和唤醒49
- 4.6 抢占和上下文切换51
- 4.6.1 用户抢占53
- 4.6.2 内核抢占53
- 4.7 实时调度策略54
- 4.8 与调度相关的系统调用54
- 4.8.1 与调度策略和优先级相关的系统调用55
- 4.8.2 与处理器绑定有关的系统调用55
- 4.8.3 放弃处理器时间56
- 4.9 小结56
- 第5章 系统调用57
- 5.1 与内核通信57
- 5.2 API、POSIX和C库57
- 5.3 系统调用58
- 5.3.1 系统调用号59
- 5.3.2 系统调用的性能59
- 5.4 系统调用处理程序60
- 5.4.1 指定恰当的系统调用60
- 5.4.2 参数传递60
- 5.5 系统调用的实现61
- 5.5.1 实现系统调用61
- 5.5.2 参数验证62
- 5.6 系统调用上下文64
- 5.6.1 绑定一个系统调用的最后步骤65
- 5.6.2 从用户空间访问系统调用67
- 5.6.3 为什么不通过系统调用的方式实现68
- 5.7 小结68
- 第6章 内核数据结构69
- 6.1 链表69
- 6.1.1 单向链表和双向链表69
- 6.1.2 环形链表70
- 6.1.3 沿链表移动71
- 6.1.4 Linux?内核中的实现71
- 6.1.5 操作链表73
- 6.1.6 遍历链表75
- 6.2 队列78
- 6.2.1 kfifo79
- 6.2.2 创建队列79
- 6.2.3 推入队列数据79
- 6.2.4 摘取队列数据80
- 6.2.5 获取队列长度80
- 6.2.6 重置和撤销队列80
- 6.2.7 队列使用举例?81
- 6.3 映射?81
- 6.3.1 初始化一个idr82
- 6.3.2 分配一个新的UID82
- 6.3.3 查找UID83
- 6.3.4 删除UID84
- 6.3.5 撤销idr84
- 6.4 二叉树84
- 6.4.1 二叉搜索树84
- 6.4.2 自平衡二叉搜索树?85
- 6.5 数据结构以及选择?87
- 6.6 算法复杂度88
- 6.6.1 算法88
- 6.6.2 大o?符号88
- 6.6.3 大θ符号89
- 6.6.4 时间复杂度89
- 6.7 小结?90
- 第7章 中断和中断处理91
- 7.1 中断91
- 7.2 中断处理程序92
- 7.3 上半部与下半部的对比93
- 7.4 注册中断处理程序93
- 7.4.1 中断处理程序标志94
- 7.4.2 一个中断例子95
- 7.4.3 释放中断处理程序95
- 7.5 编写中断处理程序96
- 7.5.1 共享的中断处理程序97
- 7.5.2 中断处理程序实例97
- 7.6 中断上下文99
- 7.7 中断处理机制的实现100
- 7.8 /proc/interrupts102
- 7.9 中断控制103
- 7.9.1 禁止和激活中断103
- 7.9.2 禁止指定中断线105
- 7.9.3 中断系统的状态105
- 7.10 小结106
- 第8章 下半部和推后执行的工作107
- 8.1 下半部107
- 8.1.1 为什么要用下半部108
- 8.1.2 下半部的环境108
- 8.2 软中断110
- 8.2.1 软中断的实现111
- 8.2.2 使用软中断113
- 8.3 tasklet114
- 8.3.1 tasklet的实现114
- 8.3.2 使用tasklet116
- 8.3.3 老的BH机制119
- 8.4 工作队列120
- 8.4.1 工作队列的实现121
- 8.4.2 使用工作队列124
- 8.4.3 老的任务队列机制126
- 8.5 下半部机制的选择127
- 8.6 在下半部之间加锁128
- 8.7 禁止下半部128
- 8.8 小结129
- 第9章 内核同步介绍131
- 9.1 临界区和竞争条件131
- 9.1.1 为什么我们需要保护132
- 9.1.2 单个变量133
- 9.2 加锁134
- 9.2.1 造成并发执行的原因135
- 9.2.2 了解要保护些什么136
- 9.3 死锁137
- 9.4 争用和扩展性138
- 9.5 小结140
- 第10章 内核同步方法141
- 10.1 原子操作141
- 10.1.1 原子整数操作142
- 10.1.2 64位原子操作144
- 10.1.3 原子位操作145
- 10.2 自旋锁147
- 10.2.1 自旋锁方法148
- 10.2.2 其他针对自旋锁的操作149
- 10.2.3 自旋锁和下半部150
- 10.3 读-写自旋锁150
- 10.4 信号量152
- 10.4.1 计数信号量和二值信号量153
- 10.4.2 创建和初始化信号量154
- 10.4.3 使用信号量154
- 10.5 读-写信号量155
- 10.6 互斥体156
- 10.6.1 信号量和互斥体158
- 10.6.2 自旋锁和互斥体158
- 10.7 完成变量158
- 10.8 BLK:大内核锁159
- 10.9 顺序锁160
- 10.10 禁止抢占161
- 10.11 顺序和屏障162
- 10.12 小结165
- 第11章 定时器和时间管理166
- 11.1 内核中的时间概念166
- 11.2 节拍率:HZ167
- 11.2.1 理想的HZ值168
- 11.2.2 高HZ的优势169
- 11.2.3 高HZ的劣势169
- 11.3 jiffies170
- 11.3.1 jiffies的内部表示171
- 11.3.2 jiffies?的回绕172
- 11.3.3 用户空间和HZ173
- 11.4 硬时钟和定时器174
- 11.4.1 实时时钟174
- 11.4.2 系统定时器174
- 11.5 时钟中断处理程序174
- 11.6 实际时间176
- 11.7 定时器178
- 11.7.1 使用定时器178
- 11.7.2 定时器竞争条件180
- 11.7.3 实现定时器180
- 11.8 延迟执行181
- 11.8.1 忙等待181
- 11.8.2 短延迟182
- 11.8.3 schedule_timeout()183
- 11.9 小结185
- 第12章 内存管理186
- 12.1 页186
- 12.2 区187
- 12.3 获得页189
- 12.3.1 获得填充为0的页190
- 12.3.2 释放页191
- 12.4 kmalloc()191
- 12.4.1 gfp_mask标志192
- 12.4.2 kfree()195
- 12.5 vmalloc()196
- 12.6 slab层197
- 12.6.1 slab层的设计198
- 12.6.2 slab分配器的接口200
- 12.7 在栈上的静态分配203
- 12.7.1 单页内核栈203
- 12.7.2 在栈上光明正大地工作203
- 12.8 高端内存的映射204
- 12.8.1 永久映射204
- 12.8.2 临时映射204
- 12.9 每个CPU的分配20512.10 新的每个CPU接口206
- 12.10.1 编译时的每个CPU数据206
- 12.10.2 运行时的每个CPU数据207
- 12.11 使用每个CPU数据的原因208
- 12.12 分配函数的选择209
- 12.13 小结209
- 第13章 虚拟文件系统210
- 13.1 通用文件系统接口210
- 13.2 文件系统抽象层211
- 13.3 Unix文件系统212
- 13.4 VFS?对象及其数据结构213
- 13.5 超级块对象214
- 13.6 超级块操作215
- 13.7 索引节点对象217
- 13.8 索引节点操作219
- 13.9 目录项对象222
- 13.9.1 目录项状态222
- 13.9.2 目录项缓存223
- 13.10 目录项操作224
- 13.11 文件对象225
- 13.12 文件操作226
- 13.13 和文件系统相关的数据结构230
- 13.14 和进程相关的数据结构232
- 13.15 小结233
- 第14章 块I/O层234
- 14.1 剖析一个块设备234
- 14.2 缓冲区和缓冲区头235
- 14.3 bio结构体237
- 14.3.1 I/O向量238
- 14.3.2 新老方法对比239
- 14.4 请求队列240
- 14.5 I/O调度程序240
- 14.5.1 I/O调度程序的工作241
- 14.5.2 Linus?电梯241
- 14.5.3 最终期限I/O调度程序242
- 14.5.4 预测I/O调度程序244
- 14.5.5 完全公正的排队I/O调度程序244
- 14.5.6 空操作的I/O调度程序245
- 14.5.7 I/O调度程序的选择245
- 14.6 小结246
- 第15章 进程地址空间247
- 15.1 地址空间247
- 15.2 内存描述符248
- 15.2.1 分配内存描述符249
- 15.2.2 撤销内存描述符250
- 15.2.3 mm_struct?与内核线程250
- 15.3 虚拟内存区域251
- 15.3.1 VMA标志251
- 15.3.2 VMA?操作253
- 15.3.3 内存区域的树型结构和内存区域的链表结构254
- 15.3.4 实际使用中的内存区域254
- 15.4 操作内存区域255
- 15.4.1 find_vma()256
- 15.4.2 find_vma_prev()257
- 15.4.3 find_vma_intersection()257
- 15.5 mmap()和do_mmap():创建地址区间258
- 15.6 mummap()和do_mummap():删除地址区间259
- 15.7 页表260
- 15.8 小结261
- 第16章 页高速缓存和页回写262
- 16.1 缓存手段262
- 16.1.1 写缓存262
- 16.1.2 缓存回收263
- 16.2 Linux?页高速缓存264
- 16.2.1 address_space对象264
- 16.2.2 address_space?操作266
- 16.2.3 基树267
- 16.2.4 以前的页散列表268
- 16.3 缓冲区高速缓存268
- 16.4 flusher线程268
- 16.4.1 膝上型计算机模式270
- 16.4.2 历史上的bdflush、kupdated?和pdflush270
- 16.4.3 避免拥塞的方法:使用多线程271
- 16.5 小结271
- 第17章 设备与模块273
- 17.1 设备类型273
- 17.2 模块274
- 17.2.1 Hello,World274
- 17.2.2 构建模块275
- 17.2.3 安装模块277
- 17.2.4 产生模块依赖性277
- 17.2.5 载入模块278
- 17.2.6 管理配置选项279
- 17.2.7 模块参数280
- 17.2.8 导出符号表282
- 17.3 设备模型283
- 17.3.1 kobject283
- 17.3.2 ktype284
- 17.3.3 kset285
- 17.3.4 kobject、ktype和kset的相互关系285
- 17.3.5 管理和操作kobject286
- 17.3.6 引用计数287
- 17.4 sysfs288
- 17.4.1 sysfs中添加和删除kobject?290
- 17.4.2 向sysfs中添加文件291
- 17.4.3 内核事件层293
- 17.5 小结294
- 第18章 调试295
- 18.1 准备开始295
- 18.2 内核中的bug296
- 18.3 通过打印来调试296
- 18.3.1 健壮性296
- 18.3.2 日志等级297
- 18.3.3 记录缓冲区298
- 18.3.4 syslogd和klogd298
- 18.3.5 从printf()到printk()的转换298
- 18.4 oops298
- 18.4.1 ksymoops300
- 18.4.2 kallsyms300
- 18.5 内核调试配置选项301
- 18.6 引发bug并打印信息301
- 18.7 神奇的系统请求键302
- 18.8 内核调试器的传奇303
- 18.8.1 gdb303
- 18.8.2 kgdb304
- 18.9 探测系统304
- 18.9.1 用UID作为选择条件304
- 18.9.2 使用条件变量305
- 18.9.3 使用统计量305
- 18.9.4 重复频率限制305
- 18.10 用二分查找法找出引发罪恶的变更306
- 18.11 使用Git进行二分搜索307
- 18.12 当所有的努力都失败时:社区308
- 18.13 小结308
- 第19章 可移植性309
- 19.1 可移植操作系统309
- 19.2 Linux移植史310
- 19.3 字长和数据类型311
- 19.3.1 不透明类型313
- 19.3.2 指定数据类型314
- 19.3.3 长度明确的类型314
- 19.3.4 char型的符号问题315
- 19.4 数据对齐315
- 19.4.1 避免对齐引发的问题316
- 19.4.2 非标准类型的对齐316
- 19.4.3 结构体填补316
- 19.5 字节顺序318
- 19.6 时间319
- 19.7 页长度320
- 19.8 处理器排序320
- 19.9 SMP、内核抢占、高端内存321
- 19.10 小结321
- 第20章 补丁、开发和社区322
- 20.1 社区322
- 20.2 Linux编码风格322
- 20.2.1 缩进323
- 20.2.2 switch?语句323
- 20.2.3 空格324
- 20.2.4 花括号325
- 20.2.5 每行代码的长度326
- 20.2.6 命名规范326
- 20.2.7 函数326
- 20.2.8 注释326
- 20.2.9 typedef327
- 20.2.10 多用现成的东西328
- 20.2.11 在源码中减少使用ifdef328
- 20.2.12 结构初始化328
- 20.2.13 代码的事后修正329
- 20.3 管理系统329
- 20.4 提交错误报告329
- 20.5 补丁330
- 20.5.1 创建补丁330
- 20.5.2 用Git创建补丁331
- 20.5.3 提交补丁331
- 20.6 小结332
- 参考资料333