从Linux内核出发
1、内核源码数
内核源码树由很多目录组成,而大多数目录又包含更多的子目录,源码树的根目录及其子目录如下:
目录 | 描述 |
arch | 特定体系结构的源码 |
crypto | crypto API |
ducumention | 内核源码文档 |
drivers | 设备驱动程序 |
fs | VFS和各种文件系统 |
include | 内核头文件 |
init | 内核引导和初始化 |
ipc | 进程间通信代码 |
kernel | 像调度程序这样的核心子系统 |
lib | 调用内核函数 |
mm | 内存管理子系统和VM |
net | 网络子系统 |
scripts | 编译内核所用的脚本 |
security | linux安全模块 |
sound | 语音子系统 |
usr | 早期用户空间代码 |
2、内核开发的特点
- 内核编程时不能访问C库
- 内核编程时必须使用GNU C
- 内核编程时却反像用户空间那样的内存保护机制
- 内核编程时浮点数很难使用
- 内核只有一个很小的定长堆栈
- 由于内核支持异步中断、抢占和SMP,因此必须时刻注意同步和并发
- 要考虑可移植性的重要性
3、内核代码使用到的C语言扩展
- 内联函数
GNU的C编译器支持内联函数,inline反应它的工作方式,函数会在它调用的位置上展开,这么做可以消除函数点永和返回所带来的开销。内联函数必须在使用之前就定义好,否则编译器就没法把这个函数展开。实践中一般在头文件中定义内联函数。由于使用了static作为关键字进行限制,所以编译器不会为内联函数单独建立一个函数体。
- 内联汇编
gcc编译器支持在C函数中嵌入汇编指令。Linux内核混合使用了C和汇编语言。在偏近体系结构的底层或对执行时间要求严格的地方,一般使用的是汇编语言,而内核其他部分的大部分代码是C语言编写的。
- 分支说明
对于条件选择语句,gcc内奸了一条指令用于优化,在一个条件经常出现,或者该条件很少出现的时候,编译器可以根据这条指令对条件分支选择进行优化。
4、没有内存保护机制
如果一个用户程序试图进行一次非法的内存访问,内核会发现这个错误,发送SIGSEGV,并结束整个进程。然而,如果是内核自己非法访问了内存,那后果就很难控制了。内核中发生的内存错误会导致oops,这是内核中出现的最常见的错误。而且,内核中的内存都不分页,没用掉一个字节,物理内存就减少一个字节。
5、不要轻易在内核中使用浮点数
在用户空间的进程内进行浮点操作的时候,内核会完成从证书操作到浮点数操作的模式转换。
6、容积小而固定的栈
内核站的准确大小随体系结构而变。
7、同步和并发
内核和容易产生竞争条件。和单线程的用户空间程序不同,内核的许多特性都要求能够冰法的访问共享数据,这就要求由同步机制保证不会出现竞争条件。
- Linux是抢占多任务操作系统。内核的进程调度程序即兴对进程进行调度和重新调度。内核必须对这些任务同步。
- Linux内核支持多处理器系统。所以,如果没有适当的保护,在两个或两个以上的处理器上运行的代码可能会同时访问共享的同一个资源。
- 中断时异步到来的,完全不顾及当前正在执行的代码。也就是说,如果不加以适当的保护,终端完全有可能在代码放翁共享资源的当中到来,这样,中断处理程序就有可能访问同一资源。
- Linux内核可以抢占。
8、可移植性的重要性