第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使用Git 10
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 GNUC 16
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 forkO 27
3.3.3 vforkO 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 kfifo 79
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初始化一个idr 82
6.3.2分配一个新的UID 82
6.3.3查找UID 83
6.3.4删除UID 84
6.3.5撤销idr 84
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/interrupts 102
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 tasklet 114
8.3.1 tasklet的实现 114
8.3.2使用 tasklet 116
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节拍率:HZ 167
11.2.1理想的HZ值 168
11.2.2高HZ的优势 169
11.2.3高HZ的劣势 169
11.3 jiffies 170
11.3.1 jiffies的内部表示 171
11.3.2 jiffies的回绕 172
11.3.3用户空间和HZ 173
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 timeoutO 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 kmallocO 191
12.4.1 gfp_mask标志 192
12.4.2 kfreeO 195
12.5 vmallocO 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的分配 205
12.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_vmaO 256
15.4.2 find_vma_prevO 257
15.4.3 find_vma_intersectionO 257
15.5 mmapO和do_mmapO:创建地址区间 258
15.6 mummapO和do_mummapO:删除地址区间 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 fiusher线程 268
16.4.1膝上型计算机模式 270
16.4.2历史上的bdflush、kupdated和pdflush 270
16.4.3避免拥塞的方法:使用多线程 271
16.5小结 271
第17章 设备与模块 273
17.1设备类型 273
17.2模块 274
17.2.1 Hello,World 274
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 kobject 283
17.3.2 ktype 284
17.3.3 kset 285
17.3.4 kobject、ktype和kset的相互关系 285
17.3.5管理和操作kobject 286
17.3.6引用计数 287
17.4 sysfs 288
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内核中的bug 296
18.3通过打印来调试 296
18.3.1健壮性 296
18.3.2日志等级 297
18.3.3记录缓冲区 298
18.3.4 syslogd和klogd 298
18.3.5从printfO到printkO的转换 298
18.4 oops 298
18.4.1 ksymoops 300
18.4.2 kallsyms 300
18.5内核调试配置选项 301
18.6引发bug并打印信息 301
18.7神奇的系统请求键 302
18.8内核调试器的传奇 303
18.8.1 gdb 303
18.8.2 kgdb 304
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 typedef 327
20.2.10多用现成的东西 328
20.2.11在源码中减少使用ifdef 328
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