《Linux内核设计与实现》读书笔记 第二章 从内核出发
一、获取内核源码
1. Git
git实际上是一种开源的分布式版本控制工具。
Linux作为一个开源的内核,其源代码也可以用git下载和管理
- 获取最新提交到版本树的一个副本
- $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
- 下载代码后,更新自己的分支到最新分支
- $ git pull
2.安装内核源代码
压缩形式为bzip2:
$ tar xvjf linux-x.y.z.tar.bz2
压缩形式为zip:
$ tar xvzf linux-x.y.z.tar.gz
关于参数:
-x 解开.tar格式的文件
-v 显示详细信息
-j 使用bzip2程序
-z 使用gzip程序
-f 使用归档文件
3. 使用补丁
从内部源码树开始,运行$ patch -p1 < ../patch-x,y,z
二、内核源码结构
详见LINUX内核分析第三周学习总结:构造一个简单的LINUX系统MENUOS中第一部分:“Linux内核源码简介”。
目 录 | 描 述 |
---|---|
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 | 虚拟化基础结构 |
- COPYIN:内核许可证
- CREDITS:开发者列表
- MAINTAINTERS:维护者列表(维护内核子系统和驱动程序)
三、编译内核
1. 配置内核(关于make与config)
(1)相关
- Makefile:根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成 Linux 内核二进制文件。
- config.in:内核配置文件,给用户提供配置选择的功能。
- 配置工具:包括配置命令解释器(
make config
)和配置用户界面(例如:make menuconfig
:基于ncurse库的图形界面工具;make gconfig
:基于gtk+的图形工具...)。 - .config:用户用来存放内核配置后结果的文件。
- 可以配置的各种选项:用CONFIG_FEATURE形式表示,其前缀为CONFIG。
(2)命令
- make config:遍历所有配置项,并让用户选择
- make deconfig:按默认的配置
- make oldconfig:先将
/boot
目录下的配置文件写进.config
文件中,采用的是注释的形式写进新增加的功能。 - zcat /proc/config.gz > .config:配置选项
CONFIG_IKCONFIG_PROC
会把完整的压缩过的内核配置文件存放在/proc/config.gz
中,再次编译时可以方便地克隆当前的配置。 - make:默认的Makefile自动化编译。
2. 其它事项
减少垃圾信息
$ make > ../detritus
#将错误报告和警告信息重定向到文件中
$ make > /dev/null
#将无用的输出信息重定向到/dev/null中 - /dev/null:空设备,输入的信息直接丢弃
衍生多个编译作业:make程序能把编译过程拆分成多个并行的作业。其中每个作业独立并发地运行,有助于加快多处理器系统上的编译过程,也有利于改善处理器的利用率。默认情况下,make只衍生一个作业。
$ make -jn
#以多个作业编译内核 - j:指定同时执行多任务
- n:要衍生出的作业数
3. 安装新内核
make modules_install
#把所有已编译的模块安装到正确的主目录/lib/modules下
- System.map文件:编译时在内核代码树的根目录下创建的
符号对照表
。用来将内核符号与它们的起始地址对应起来。
四、内核开发特点
1. 无libc库/标准头文件
原因:(速度与大小)保证内核高效和简练。
内核源代码文件不能包含外部头文件。
- 基本头文件:内核源代码顶级目录下的
include
中 - 体系结构相关头文件:内核源代码树的
arch/<architecture>/include/asm
目录下
- 基本头文件:内核源代码顶级目录下的
printk()函数:把格式化好的字符串拷贝到内核日志缓冲区上,syslog程序可以通过读取该缓冲区来获取内核信息。
2. 必须使用GNU C
什么是GNU?GNU是一种操作系统,GNU提供的C编译器就是我们之前使用的gcc。
(1)内联函数
static inline void wolf(unsigned long tail_size);
- static:关键字
- inline:用于限定关键字
内联函数:编译时在它被调用的地方展开。
- 优点:减少了函数调用的开销,性能较好。
- 缺点:频繁的使用内联函数也会使代码变长,从而在运行时占用更多的内存。
定义内联函数特点:时间要求高,本身长度较短的函数。
使用之前就要定义好内联函数,一般在头文件中定义。
为了类型安全和易读性,优先使用内联函数而不是复杂的宏。
(2)内联汇编
unsigned int low, high;
asm volatile("rdtsc" : "=a" (low), "=d" (high));
/* low 和 high 分别包含64位时间戳的低32位和高32位 */
- asm:嵌入汇编代码
- volatile:不优化
- 汇编语言用于偏近底层或对执行时间严格要求的地方。
(3)分支声明
/* 如果error在绝大多数情况下为0(假) */
if (unlikely(error)) {
/* ... */
}
/* 如果success在绝大多数情况下不为0(真) */
if (likely(success)) {
/* ... */
}
- 对于条件选择语句,在一个条件经常/很少出现时,编译器可通过gcc内建的一条指令对条件分支选择进行优化。
- 内核把这条指令封装成了宏。
3. 没有内存保护机制
- 内核自己非法访问内存的风险
- 内核中的内存都不分页:每用掉一个字节,物理内存都减少一个
4. 难以执行浮点运算
- 使用浮点数时,需要人工保存和恢复浮点寄存器及其他一些繁琐的操作。
- 不建议使用
5. 每个进程只有一个很小的定长堆栈
- 内核栈的大小是编译内核时决定的,对于不用的体系结构,内核栈的大小不一样,但都是固定的。(不像用户空间的栈可以动态增长)
6. 必须时刻注意同步和并发
原因:
- Linux是抢占多任务操作系统
- 内核支持对称多处理器系统(SMP)
- 中断异步到来
- 内核可以抢占
常用解决方法:自旋锁和信号量
7. 考虑可移植性的重要性
- 需要保持的特点:大部分C语言代码与体系结构无关。
五、总结:关于Linux内核的结构与特点
1. 版本控制
- 我最早接触git是刚开始使用实验楼的时候,实验楼中的代码保存需要用到其中“我的代码库”功能,实际上就是最简单的git。
- Linux内核这种开源的代码以及很多项目使用git进行版本控制与协作都是挺方便的。
- 网上有很多教程可以参考,感觉这个比较全面:Git教程,可以在一些网站上创建自己的代码库,比如:git.oschina,操作过就会发现还是比较简单的。
2. 依据结构和特点的开发
- 通读本章之后感觉Linux内核的很多要求与一般的项目其实是差不多的,它的这些基本结构、开发的特点,对于理解它各个部分的工作过程是很有帮助的。
参考资料1:《Linux内核设计与实现》(原书第三版)
参考资料2:make config 解惑
《Linux内核设计与实现》读书笔记 第二章 从内核出发的更多相关文章
- Linux内核设计与实现 读书笔记 转
Linux内核设计与实现 读书笔记: http://www.cnblogs.com/wang_yb/tag/linux-kernel/ <深入理解LINUX内存管理> http://bl ...
- Linux内核设计与实现 读书笔记
第三章 进程管理 1. fork系统调用从内核返回两次: 一次返回到子进程,一次返回到父进程 2. task_struct结构是用slab分配器分配的,2.6以前的是放在内核栈的栈底的:所有进程的ta ...
- STL源码分析读书笔记--第二章--空间配置器(allocator)
声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...
- Spring 3.x 实践 第一个例子(Spring 3.x 企业应用开发实战读书笔记第二章)
前言:工作之后一直在搞android,现在需要更多和后台的人员交涉,技术栈不一样,难免鸡同鸭讲,所以稍稍学习下. 这个例子取自于<Spring 3.x 企业应用开发实战>一书中的第二章,I ...
- Getting Started With Hazelcast 读书笔记(第二章、第三章)
第二章 起步 本章就相当简单粗暴了,用一个个例子说明hazelcast怎么用. 1.map,set,list这些集合类都是开箱即用的,只要从Hazelcast的实例中获取一份就行. 2.增加了Mult ...
- Java Concurrency in Practice 读书笔记 第二章
第二章的思维导图(代码迟点补上):
- javascript 数据结构和算法读书笔记 > 第二章 数组
这章主要讲解了数组的工作原理和其适用场景. 定义: 一个存储元素的线性集合,元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量. javascript数组的特殊之处: jav ...
- 《C++ Primer》读书笔记—第二章 变量和基本类型
声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程. 1.8比特的char类型计算机表示的实际范围是-12 ...
- [Effective Java 读书笔记] 第二章 创建和销毁对象 第一条
第二章 创建和销毁对象 第一条 使用静态工厂方法替代构造器,原因: 静态工厂方法可以有不同的名字,也就是说,构造器只能通过参数的不同来区分不同的目的,静态工厂在名字上就能表达不同的目的 静态工厂方法 ...
随机推荐
- EntityFramework 基础的crud
EntityFramework 基础的crud操作 根据上一张实体映射的demo学习基础的crud操作 1.增加 BlogDbContext dbContext = new BlogDbContext ...
- LeetCode() Word Search II
超时,用了tire也不行,需要再改. class Solution { class TrieNode { public: // Initialize your data structure here. ...
- MPI运行程序(接触)
网友遇到的问题并解决问题:mpich2在多个节点上运行并行程序时出错 我使用mpich2时遇到一下问题: 当我运行一个计算圆周率的并行程序cpi.c时,我想在指定的若干个节点上运行这个程序,比如hos ...
- django 过滤器 、日期格式化参数
http://blog.csdn.net/xyp84/article/details/7945094 django1.4 html页面从数据库中读出DateTimeField字段时,显示的时间格式和数 ...
- spring技术核心概念纪要
一.背景 springframework 从最初的2.5版本发展至今,期间已经发生了非常多的修正及优化.许多新特性及模块的出现,使得整个框架体系显得越趋庞大,同时也带来了学习及理解上的困难. 本文阐述 ...
- 鼠标滚动事件兼容性 wheel、onwheel
wheelEvent = "onwheel" in document.createElement("div") ? "wheel" : // ...
- Eclipse插件SVN配置
Eclipse插件SVN配置 方法一 打开Eclipse点击[Help]-[Install New Software] 点击右边[Add]-在弹出窗口中输入 Name:svn Location:htt ...
- [HTML5]块和内联元素的嵌套
块元素可以包含块或内联元素,但是内联元素只能包含其他内联元素. <!-- 无效代码! :-( --> <strong> <p>你不应该把p元素放在 "st ...
- DataTable排序(转)
DataTable 排序 DataRow[] rows = dataTable1.Select("", "ord asc"); DataTable t ...
- [CF #288-C] Anya and Ghosts (贪心)
题目链接:http://codeforces.com/contest/508/problem/C 题目大意:给你三个数,m,t,r,代表晚上有m个幽灵,我有无限支蜡烛,每支蜡烛能够亮t秒,房间需要r支 ...