《Linux内核设计与实现.第3版》1-2章学习笔记
1. 获取内核源码
http://www.kernel.org
2. 内核版本命名规则
内核的版本号主要有四个数字组成。
从版本号: 偶数表示稳定版(可用于企业级环境),奇数表示开发版;
修订版本号: 包括BUG修正,新的驱动以及新的特性的追加;
稳定版本号: 关键性BUG的修改;
3. 单内核和微内核
原理 | 优势 | 劣势 | |
---|---|---|---|
单内核 | 整个内核都在一个大内核地址空间上运行。 | 简单、高效: 所有内核都在一个大的地址空间上,所以内核各个功能之间的调用和调用函数类似,几乎没有性能开销。 | 一个功能的崩溃会导致整个内核无法使用。 |
微内核 | 内核按功能被划分成各个独立的过程。每个过程独立的运行在自己的地址空间上。 | 安全: 内核的各种服务独立运行,一种服务挂了不会影响其他服务。 | 内核各个服务之间的调用涉及进程间的通信,比较复杂且效率低。 |
Linux内核是基于单内核的,但也具备微内核的一些特征:(体现了Linux实用至上的原则)
- 支持动态加载内核模块
- 支持对称多处理(SMP)
- 内核可以抢占(preemptive),允许内核运行的任务有优先执行的能力
- 不区分线程和进程
4. 内核源码的结构
目录 | 说明 |
---|---|
arch | 特定体系结构的代码 |
block | 块设备I/O层 |
crypo | 加密API |
Documentation | 内核源码文档 |
drivers | 设备驱动程序 |
firmware | 使用某些驱动程序而需要的设备固件 |
fs | VFS和各种文件系统 |
include | 内核头文件 |
init | 内核引导和初始化 |
ipc | 进程间通信代码 |
kernel | 像调度程序这样的核心子系统 |
lib | 库文件代码 |
mm | 内存管理子系统和VM |
net | 网络子系统 |
samples | 内核编程案例 |
scripts | 配置裁剪内核的工具脚本 |
security | 包括不同的Linux安全模型代码 |
sound | 音频设备的驱动程序 |
usr | 早期用户空间代码(所谓的initramfs) |
tools | 在Linux开发中有用的工具 |
virt | 虚拟化基础结构 |
5. 编译内核的方法
# 1.通过命令图形用户界面化配置,生成.config配置文件
$ sudo make menuconfig
# 2.内核编译
$ sudo make -j4
# 3.安装模块
$ sudo make modules_install
# 4.安装内核
$ sudo make install
# 5.reboot系统,重新选择内核版本,启动后通过以下指令查看内核版本
$ uname -a
修改ubuntu启动时选择内核:
# step1: 修改grub文件
$ sudo vim /etc/default/grub
GRUB_DEFAULT=0
#GRUB_TIMEOUT_STYLE=hidden # 1.屏蔽此处
GRUB_TIMEOUT=30 # 2.修改等待时间为30s
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
# step2:更新grub配置
$ sudo update-grub
6. 内核开发的特点
-
无标准C库: 为了保证内核的小和高效,内核开发中不能使用C标准库,例如
printk
替代printf
; -
GNU C 扩展:
-
内联函数: 内联函数在编译时会在它被调用的地方展开,减少了函数调用的开销,性能较好。
但频繁的使用内联函数也会使代码变长,从而在运行时占用更多的内存。
**所以使用内联函数时要求:**函数较小,会被反复调用,对程序的时间要求比较严格。
/*EG:*/ static inline void sample();
-
内联汇编: 内联汇编用于偏近底层或对执行时间严格要求的地方。
unsigned int low, high; /* low 和 high 分别包含64位时间戳的低32位和高32位 */ asm volatile("rdtsc" : "=a" (low), "=d" (high));
-
分支声明: 如果能事先判断一个if语句时经常为真还是经常为假,那么可以用unlikely和likely来优化这段判断的代码
if (unlikely(error)) /* 如果error在绝大多数情况下为0(假) */ if (likely(success)) /* 如果success在绝大多数情况下不为0(真) */
-
-
没有内存保护: 因为内核是最低层的程序,所以如果内核访问的非法内存,那么整个系统都会挂掉,所以内核开发的风险比用户程序开发的风险要大。
而且,内核中的内存是不分页的,每用一个字节的内存,物理内存就少一个字节。所以内核中使用内存一定要谨慎。
-
不使用浮点数: 内核不能完美的支持浮点操作,使用浮点数时,需要人工保存和恢复浮点寄存器及其他一些繁琐的操作。
-
内核栈容积小且固定: 内核栈的大小有编译内核时决定的,对于不用的体系结构,内核栈的大小虽然不一样,但都是固定的。
$ ulimit -a | grep "stack size" # 查看内核栈大小的方法 stack size (kbytes, -s) 8192
-
同步和并发: Linux是多用户的操作系统,所以必须处理好同步和并发操作,防止因竞争而出现死锁。
-
可移植性: Linux内核可用于不用的体现结构,支持多种硬件。所以开发时要时刻注意可移植性,尽量使用体系结构无关的代码。