《Linux内核设计与实现》课本学习笔记
By20135203齐岳
一、Linux内核简介
Unix内核的特点
- Unix很简洁,所提供的系统调用都有很明确的设计目的。
- Unix中一切皆文件,对数据和设备的操作都是通过一套相同的系统调用接口进行的。
- Unix内核和相关的系统工具都是用C语言编写成的。
- Unix进程创建非常迅速。
- Unix提供了一套简单而稳定的进程间通信原语。
Unix现在已经发展为一个支持抢占式多任务、多线程、虚拟内存、换页、动态链接和TCP/IP网络的现代化操作系统。
操作系统与内核
操作系统是计算机完成基本功能和系统管理的核心,内核是操作系统的核心。在系统中运行的应用程序通过系统调用来与内核通信。
内核提供的服务主要有:
- 中断服务程序,负责响应响应中断
- 调度程序,负责管理多个进程从而分配处理器轮转时间
- 内存管理程序,管理进程地址空间
- 网络、进程间通信等系统服务
Linux与Unix的联系
- Linux是类Unix系统,但不是Unix,也没有直接使用Unix的源代码。
- Linux内核是*公开的软件,开源。
- Linux是单内核,但汲取了微内核的精华:模块化设计、抢占式内核、支持内核线程以及动态装载内核模块的能力。
单内核与微内核
单内核:内核通常以单个静态二进制文件的形式存放于磁盘中所有内核服务都运行在内核态并身处同一地址空间,内核可以直接调用函数。特点是简单,性能高。
微内核:不同的功能被划分为独立的过程,每个过程叫做一个服务器,通过消息传递处理微内核通信,采用了进程间通信(IPC)机制。
二、内核源代码
获取内核源代码
使用Git来获取最新版本源代码:
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
更新到Linux的最新分支:
$ git pull
解压并安装内核源代码:
$ tar xvjf linux-x.y.z.tar.bz2/gz
使用补丁:
$ patch -p1 < ../patch-x.y.z
注意:内核源码一般都安装在/usr/src/linux目录下,但不能把这个源码树用于内核开发,或者以root身份对内核进行修改。
内核源码树
三、编译内核
配置内核
Linux中可以配置的选项其前缀均为CONFIG。
配置项二选一:yes 或 no
配置项三选一:yes 、no 或 module(以模块形式生成,为独立代码段)
简化内核配置工具:
-
字符界面下的Linux工具:逐一遍历所有的配置项,要求用户逐一选择,耗时长。
$ make config
-
基于ncurse库编制的图形界面工具:
$ make menuconfig
-
基于gtk+的图形工具:
$ make gconfig
-
基于默认配置为体系结构创建一个配置:
$ make defconfig
-
验证和更新配置:
$ make oldconfig
一旦内核配置好,就可以利用一个简单的命令来编译它。
$ make
减少编译的垃圾信息
尽量减少垃圾信息的方法:对输出进行重定向。
$ make > .. /detritus 将输出信息重定向到这个文件目录
$ make > /dev/null 把无用的输出信息重定向到永无返回值的黑洞/dev/null
衍生多个编译作业
以多个作业编译内核:
$ make jn n为要衍生出的作业数,每个处理器可以衍生出1或2个作业,16核时n可取32
安装新内核
$ make modules_install
编译时会在内核代码目录树的根目录下创建一个System.map文件,为符号对照表,用于将内核符号和他们的起始地址对应起来,方便调试。
四、内核开发特点
无libc库或标准头文件
大部分常用的C库函数在内核中都已经得到实现,只要包含<linux/string.h>文件就可以使用它们。
GUN C
内联函数
内联函数的工作模式:函数会在它所调用的位置上展开,可以消除函数调用和返回所带来的开销(寄存器存储和恢复)。但是代码会变长,占用更多的内存空间或者缓存指令。
定义一个内联函数的时候需要使用static作为关键字并用inline限定,并且必须在使用之间就定义好。
static inline void wolf(unsigned long tail_size)
内联汇编
gcc编译器支持在C函数中嵌入汇编指令。通常使用asm()指令嵌入汇编代码。
分支声明
对于条件选择语句,在一个条件经常出现或很少出现的时候,编译器可以根据这条指令对条件分支进行选择优化。并将其封装成宏,如likely()和unlikely()。
-
将一个选择标记成绝少发生的分支:
/*error绝大多数时间都会为0*/
if(unlikely(error)){
...
} -
将一个分支标记为通常为真的分支:
/*success通常都不会为0*/
if(likely(success)){
...
}
没有内存保护机制
- 内核中发生内存错误会导致oops。访问非法地址或引用空指针可能会造成死机。
- 内核中所有的内存都不分页。每使用一个字节,物理内存就减少一个字节。
同步和并发
内核很容易产生竞争条件,许多性能要求并发地共享访问数据。通常解决竞争的办法是自旋锁和信号量。
- Linux是抢占式多任务操作系统。
- Linux内核支持对称处理器系统(SMP)。
- 中断是异步到来的,完全不考虑当前正在执行的代码。
- Linux内核可以抢占。