编辑推荐
1.原理 基础,从调试Linux内核到动手编写一个简单的内核模块,真正从零开始学习Linux内核。2.实验 案例,70余个创新实验贯穿全书,与你分享业内一线项目经验。3.课件 视频,教学资源丰富,视频讲解透彻,与你共享精品在线配套资源(可在异步社区下载)。4.涵盖当前Linux社区中新的开发工具和社区运作方式,反映Linux内核社区新发展。
内容简介
本书是一本介绍Linux内核实践的入门书,基于Linux 4.0内核,重点讲解Linux内核的理论和实验。本书分为12章,包括Linux系统入门、Linux内核基础知识、内核编译和调试、内核模块、简单的字符设备驱动、系统调用、内存管理、进程管理、同步管理、中断管理、调试和性能优化,以及如何参与开源社区等内容。此外,本书还介绍了Linux内核社区常用的开发工具和理论,如Vim 8和git工具等。书中包括70多个实验,帮助读者深入理解Linux内核。
作者简介
张天飞,笔名“笨叔叔”,Linux内核爱好者,从事Linux内核和驱动开发十余年,曾在多家芯片公司从事过手机芯片底层软件开发和客户支持工作。著有《奔跑吧 Linux内核》一书。
目录
- 第 1章 Linux系统入门 1
- 1.1 Linux的发展历史 1
- 1.2 Linux发行版 2
- 1.2.1 Red Hat Linux 2
- 1.2.2 Debian Linux 3
- 1.2.3 SuSE Linux 4
- 1.2.4 优麒麟Linux 4
- 1.3 Linux内核 5
- 1.3.1 宏内核和微内核 5
- 1.3.2 Linux内核概貌 6
- 1.4 如何学习Linux内核 9
- 1.5 Linux内核实验入门 10
- 1.5.1 实验1:在虚拟机中安装
- 优麒麟Linux 18.04系统 10
- 1.5.2 实验2:给优麒麟Linux系统
- 更换“心脏” 14
- 1.5.3 实验3:使用定制的内核
- runninglinuxkernel 15
- 1.5.4 实验4:如何编译和运行一个
- ARM Linux内核 19
- 第 2章 Linux内核基础知识 22
- 2.1 Linux常用的编译工具 22
- 2.1.1 GCC工具 22
- 2.1.2 ARM GCC 23
- 2.1.3 GCC编译 24
- 2.2 Linux内核中常用的C语言技巧 25
- 2.3 Linux内核中常用的数据结构和
- 算法 31
- 2.3.1 链表 31
- 2.3.2 红黑树 34
- 2.3.3 无锁环形缓冲区 36
- 2.4 Vim工具的使用 38
- 2.4.1 Vim 8介绍 38
- 2.4.2 Vim的基本模式 38
- 2.4.3 Vim中3种模式的切换 39
- 2.4.4 Vim光标的移动 40
- 2.4.5 删除、复制和粘贴 41
- 2.4.6 查找和替换 41
- 2.4.7 文件相关 41
- 2.5 git工具的使用 42
- 2.5.1 安装git 43
- 2.5.2 git基本操作 43
- 2.5.3 分支管理 46
- 2.6 实验 48
- 2.6.1 实验1:GCC编译 48
- 2.6.2 实验2:内核链表 51
- 2.6.3 实验3:红黑树 52
- 2.6.4 实验4:使用Vim工具 52
- 2.6.5 实验5:把Vim打造成一个
- 强大的IDE编辑工具 52
- 2.6.6 实验6:建立一个git本地
- 仓库 60
- 2.6.7 实验7:解决合并分支
- 冲突 62
- 2.6.8 实验8:利用git来管理Linux
- 内核开发 65
- 2.6.9 实验9:利用git来管理项目
- 代码 67
- 第3章 内核编译和调试 73
- 3.1 内核配置 73
- 3.1.1 内核配置工具 73
- 3.1.2 .config文件 74
- 3.2 实验1:通过QEMU调试ARM Linux
- 内核 76
- 3.3 实验2:通过QEMU调试ARMv8的
- Linux内核 78
- 3.4 实验3:通过Eclipse+QEMU单步调
- 试内核 81
- 3.5 实验4:在QEMU中添加文件系统的
- 支持 85
- 第4章 内核模块 86
- 4.1 从一个内核模块开始 86
- 4.2 模块参数 90
- 4.3 符号共享 92
- 4.4 实验 93
- 4.4.1 实验1:编写一个简单的内核
- 模块 93
- 4.4.2 实验2:向内核模块传递
- 参数 95
- 4.4.3 实验3:在模块之间导出
- 符号 95
- 第5章 简单的字符设备驱动 96
- 5.1 实验1:从一个简单的字符设备
- 开始 97
- 5.2 字符设备驱动详解 102
- 5.2.1 字符设备驱动的抽象 102
- 5.2.2 设备号的管理 104
- 5.2.3 设备节点 104
- 5.2.4 字符设备操作方法集 105
- 5.3 实验2:使用misc机制来创建
- 设备 107
- 5.4 一个简单的虚拟设备 109
- 5.4.1 实验3:为虚拟设备编写
- 驱动 109
- 5.4.2 实验4:使用KFIFO改进
- 设备驱动 112
- 5.5 阻塞I/O和非阻塞I/O 115
- 5.5.1 实验5:把虚拟设备驱动改成
- 非阻塞模式 115
- 5.5.2 实验6:把虚拟设备驱动改成
- 阻塞模式 118
- 5.6 I/O多路复用 122
- 5.6.1 Linux的I/O多路复用 122
- 5.6.2 实验7:向虚拟设备中添加
- I/O多路复用支持 123
- 5.7 实验8:为什么不能唤醒读写
- 进程 128
- 5.8 实验9:向虚拟设备中添加异步
- 通知 129
- 5.9 本章小结 133
- 第6章 系统调用 134
- 6.1 系统调用概念 134
- 6.1.1 系统调用和POSIX标准 135
- 6.1.2 系统调用表 135
- 6.1.3 用程序访问系统调用 136
- 6.1.4 新增系统调用 137
- 6.2 实验 137
- 6.2.1 实验1:在ARM32机器上
- 新增一个系统调用 137
- 6.2.2 实验2:在优麒麟Linux机器
- 上新增一个系统调用 138
- 第7章 内存管理 139
- 7.1 从硬件角度看内存管理 139
- 7.1.1 内存管理的“远古
- 时代” 139
- 7.1.2 分段机制 141
- 7.1.3 分页机制 142
- 7.1.4 虚拟地址到物理地址的
- 转换 143
- 7.2 从软件角度看内存管理 144
- 7.2.1 free命令 144
- 7.2.2 从应用编程角度看
- 内存管理 145
- 7.2.3 从内存布局图角度看内存
- 管理 146
- 7.2.4 从进程角度看内存管理 150
- 7.3 物理内存管理 154
- 7.3.1 物理页面 155
- 7.3.2 内存管理区 159
- 7.3.3 分配和释放页面 162
- 7.3.4 分配小块内存 170
- 7.4 虚拟内存管理 177
- 7.4.1 进程地址空间 177
- 7.4.2 内存描述符mm_struct 178
- 7.4.3 VMA管理 180
- 7.4.4 malloc分配函数 183
- 7.4.5 mmap 185
- 7.5 缺页异常 188
- 7.5.1 do_page_fault函数 189
- 7.5.2 匿名页面缺页异常 190
- 7.5.3 文件映射缺页中断 190
- 7.5.4 写时复制缺页异常 191
- 7.5.5 缺页异常小结 192
- 7.6 内存短缺 193
- 7.6.1 页面回收算法 193
- 7.6.2 OOM Killer机制 194
- 7.7 内存管理实验 195
- 7.7.1 实验1:查看系统内存
- 信息 195
- 7.7.2 实验2:获取系统的物理
- 内存信息 197
- 7.7.3 实验3:分配内存 199
- 7.7.4 实验4:slab 200
- 7.7.5 实验5:VMA 201
- 7.7.6 实验6:mmap 203
- 7.7.7 实验7:映射用户内存 203
- 7.7.8 实验8:OOM 204
- 第8章 进程管理 205
- 8.1 进程 205
- 8.1.1 进程的来由 205
- 8.1.2 进程描述符 207
- 8.1.3 进程的生命周期 209
- 8.1.4 进程标识 212
- 8.1.5 进程间的家族关系 212
- 8.1.6 获取当前进程 214
- 8.2 进程的创建和终止 216
- 8.2.1 写时复制技术 216
- 8.2.2 fork()函数 217
- 8.2.3 vfork()函数 218
- 8.2.4 clone()函数 218
- 8.2.5 内核线程 219
- 8.2.6 do_fork()函数 219
- 8.2.7 终止进程 221
- 8.2.8 僵尸进程和托孤进程 222
- 8.2.9 进程0和进程1 222
- 8.3 进程调度 223
- 8.3.1 进程分类 224
- 8.3.2 进程优先级 224
- 8.3.3 时间片 225
- 8.3.4 经典调度算法 225
- 8.3.5 Linux O(n)调度算法 228
- 8.3.6 Linux O(1)调度算法 228
- 8.3.7 Linux CFS调度算法 228
- 8.3.8 进程切换 233
- 8.3.9 与调度相关的数据结构 239
- 8.4 多核调度 241
- 8.4.1 调度域和调度组 241
- 8.4.2 负载计算 244
- 8.4.3 负载均衡算法 245
- 8.5 实验 246
- 8.5.1 实验1:fork和clone 246
- 8.5.2 实验2:内核线程 247
- 8.5.3 实验3:后台守护进程 247
- 8.5.4 实验4:进程权限 247
- 8.5.5 实验5:设置优先级 247
- 8.5.6 实验6:per-cpu变量 248
- 第9章 同步管理 250
- 9.1 原子操作与内存屏障 251
- 9.1.1 原子操作 251
- 9.1.2 内存屏障 253
- 9.2 自旋锁机制 254
- 9.2.1 自旋锁定义 254
- 9.2.2 自旋锁变种 256
- 9.2.3 自旋锁和raw_spin_lock 257
- 9.2.4 自旋锁的改进 257
- 9.3 信号量 258
- 9.4 互斥体 259
- 9.5 读写锁 261
- 9.5.1 读写锁定义 261
- 9.5.2 读写信号量 262
- 9.6 RCU 264
- 9.7 等待队列 267
- 9.7.1 等待队列头 267
- 9.7.2 等待队列节点 268
- 9.8 实验 269
- 9.8.1 实验1:自旋锁 269
- 9.8.2 实验2:互斥锁 269
- 9.8.3 实验3:RCU 269
- 第 10章 中断管理 270
- 10.1 Linux中断管理机制 270
- 10.1.1 ARM中断控制器 271
- 10.1.2 硬件中断号和Linux中断
- 号的映射 275
- 10.1.3 注册中断 276
- 10.2 软中断和tasklet 278
- 10.2.1 SoftIRQ软中断 279
- 10.2.2 tasklet 280
- 10.2.3 local_bh_disable/local_bh_
- enable 281
- 10.2.4 本节小结 282
- 10.3 工作队列机制 282
- 10.3.1 工作队列类型 283
- 10.3.2 使用工作队列 285
- 10.3.3 本节小结 285
- 10.4 实验 286
- 10.4.1 实验1:tasklet 286
- 10.4.2 实验2:工作队列 286
- 10.4.3 实验3:定时器和内核
- 线程 287
- 第 11章 调试和性能优化 288
- 11.1 printk和动态输出 289
- 11.1.1 printk输出函数 289
- 11.1.2 动态输出 290
- 11.1.3 实验1:printk 292
- 11.1.4 实验2:动态输出 292
- 11.2 proc和debugfs 293
- 11.2.1 proc文件系统 293
- 11.2.2 sys文件系统 295
- 11.2.3 debugfs 296
- 11.2.4 实验3:procfs 297
- 11.2.5 实验4:sysfs 298
- 11.2.6 实验5:debugfs 300
- 11.3 ftrace 301
- 11.3.1 irqs跟踪器 302
- 11.3.2 preemptoff跟踪器 304
- 11.3.3 preemptirqsoff跟踪器 305
- 11.3.4 function跟踪器 306
- 11.3.5 动态ftrace 307
- 11.3.6 事件跟踪 308
- 11.3.7 实验6:使用frace 310
- 11.3.8 实验7:添加一个新的
- 跟踪点 311
- 11.3.9 实验8:使用示踪标志 314
- 11.3.10 实验9:使用kernelshark
- 来分析数据 317
- 11.4 实验10:分析oops错误 319
- 11.5 perf性能分析工具 323
- 11.5.1 实验11:使用perf工具来
- 进行性能分析 328
- 11.5.2 实验12:采集perf数据生成
- 火焰图 329
- 11.6 内存检测 329
- 11.6.1 实验13:使用slub_debug
- 检查内存泄漏 330
- 11.6.2 实验14:使用kmemleak
- 检查内存泄漏 335
- 11.6.3 实验15:使用kasan检查
- 内存泄漏 337
- 11.6.4 实验16:使用valgrind
- 检查内存泄漏 340
- 11.7 实验17:kdump 342
- 11.8 性能和测试 348
- 11.8.1 性能测试概述 348
- 11.8.2 实验18:使用lkp-tests工具
- 进行性能测试 349
- 第 12章 开源社区 350
- 12.1 什么是开源社区 350
- 12.1.1 开源软件的发展历史 350
- 12.1.2 Linux基金会 351
- 12.1.3 开源协议 351
- 12.1.4 Linux内核社区 353
- 12.1.5 国内开源社区 354
- 12.2 参与开源社区 354
- 12.2.1 参与开源项目的好处 354
- 12.2.2 如何参与开源项目 355
- 12.3 实验1:使用cppcheck检查
- 代码 356
- 12.4 实验2:提交* 一个Linux内核
- 补丁 357
- 12.5 实验3:管理和提交多个补丁
- 组成的补丁集 359
- 12.6 实验4:在Gitee中创建一个
- 开源项目 363
- 参考文献 366