从内核登程
原以为这章能够飞快跳过,但还是发现很多新的有意思的点。
获取源码
-
https://www.kernel.org 压缩源码或者增量补丁
- bz2
tar xvjf linux-x-y-z.tar.bz2
- gz
tar xvzf linux-x-y-x.tar.gz
- bz2
- https://github.com/torvalds/l…
装置源码
/usr/src/linux
不要把这个源码树用于开发,因为编译用的 C 库所用的内核版本就链接到这棵树。
正确:建设本人的主目录,而后仅用 root 进行装置。
对于补丁:patch -p1 < ../patch-x.y.z
内核源码树
目录 | 形容 |
---|---|
arch | 特定体系结构的源码 |
block | 块设施 io 层 |
crypto | 秘密 API |
Documents | 内核源码文档 |
drivers | 设施驱动程序 |
firmware | 应用某些驱动程序而须要的设施固件 |
fs | VFS 和各种文件系统 |
include | 内核同文件 |
init | 内核疏导和初始化 |
ipc | 过程间通信 |
kernel | 外围子系统 |
lib | 通用内核函数 |
mm | 内存管理子系统和 VM |
net | 网络子系统 |
samples | 实例 |
scripts | 编译内核所用的脚本 |
security | Linux 平安模块 |
sound | 语音子系统 |
usr | 晚期用户空间代码 |
tools | Linux 开发工具 |
virt | 虚拟化体系 |
编译
编译 Linux 之前须要进行配置:CONFIG_XXXX: yes|no|module;
- 决定哪些文件能够被编译进内核;module 意味着该配置选项被选定,但编译的时候这部分性能的实现代码是以模块的模式生成的(动静装置的独立代码块)。
- 通过预处理的命令解决代码;配置选项能够为字符串和证书,指定内核源码能够拜访的值,以预处理宏的模式;如制订动态调配数组的大小。
配置命令: - 逐个遍历
make config
- 图形界面工具
make menuconfig
- gtk+ 图形工具
make gconfig
- 默认配置
make defconfig
配置选项会被放在根目录下.config 文件中;每次编译前,更新配置make oldconfig
能够配置 CONFIG_IKCONFIG_PROC,把配置压缩放入 /proc/config.gz 下,能够从 /proc 下复制出配置文件并且应用它来编译一个新内核:zcat /proc/config.gz > .config
make oldconfig
配置实现后:make > /dev/null
进步 make 效率多核,如 16 核:make -j32 > /dev/null
;
装置
- 查阅启动疏导工具的阐明,将内核映像拷贝到 /boot 目录下,按启动要求装置。
- 内核模块的装置是主动的,
make modules_install
,装到 /lib/modules 下 - 编译时也会在内核代码树的根目录下创立一个 System.map 文件,符号对照表,将内核符号和他们的起始地址对应,须要把内存地址翻译成容易了解的函数名以及变量名。
内核开发
内核编译时不能拜访 c 库文件 (libc) 和规范 c 头文件
lib/string.c => <linux/string.h>
- 内核开发头文件根本都在源码 include 目录下,头文件 <linux/inotify.h>
- 体系相干的头文件 arch/x86/include/asm 上面 <asm/ioctl.h>
没有实现的 printf() -> prink 将格式化的字符串拷贝到日志缓冲区中,syslog 程序就能够通过读取该缓冲区来获取内核信息。能够指定一个优先级标志符,相似于宏定义prink(KERN_ERR "this is an error.\n")
应用 GNU C
- gcc 工具蕴含了多种 GNU 编译器,能够编译内核。
-
内核 C 语言蕴含了 ISO C99 规范和 GNU C 扩大个性。与规范 c 语言不同的大多是 GNU C 的扩大上。
-
内联函数 inline:
- 函数在调用地位扩大,打消函数调用和返回的开销,代码变长,占用内存空间或者指令缓存更多;
- 函数较大,被重复调用,没有工夫要求不举荐应用
- 与 static 合用
static inline void wolf(unsigned long tail_size)
- 应用前定义,举荐在头文件中定义,优先应用 inline 函数而不是宏
-
内联汇编
- 只有晓得体系结构才能够应用,偏近底层或对执行工夫要求严格
asm()
unsigned int low, hight
asm volatile("rdtsc" : "=a" (low), "=d" (high));
-
分支申明
- gcc 优化分支,经常出现 likely, unlikely
if (unlikely (error))
- 肯定要弄清是否真的有偏差,对性能影响微小
- gcc 优化分支,经常出现 likely, unlikely
没有内存保护机制
-
- 用户程序非法内存拜访,内核会发现,发送 SIGSEGV 信号,完结过程
-
内核中产生内存拜访谬误导致 oops
- 非法内存拜访
- 援用空指针
- 内核中内存不分页,用一个字节,物理内存就少一个
不要轻易应用浮点数
- 用户空间操作浮点数,内核须要从整数模式切换成内核模式,具体实现与体系相干
- 在内核中应用浮点数时,须要人工保留和回复浮点寄存器,还要有其余简单工作
内核只有小而固定的栈
- 用户空间能够动态分配大容积的栈,内核不行
- 内核栈大小随体系变动,x86,在编译时确定,4KB 或者 8KB;历史上内核栈大小两页,32 位 8KB, 64 位 16KB
留神同步和并发
起因:
- Linux 是抢占多任务操作系统,调度过程中内核必须和工作同步
- 反对对称多处理器零碎 SMP;两个或多个以上的处理器上执行的内核代码可能同时访问共享的同一个资源
- 中断异步到来,可能在拜访资源时到来,中断程序可能解决同一个资源
- Linux 内核能够抢占,内核中正在执行的代码可能被同一段代码抢占,从而导致几段代码同时拜访雷同的资源。
办法:
- 自旋锁
- 信号量