《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 读书笔记] 第二章 创建和销毁对象 第一条
第二章 创建和销毁对象 第一条 使用静态工厂方法替代构造器,原因: 静态工厂方法可以有不同的名字,也就是说,构造器只能通过参数的不同来区分不同的目的,静态工厂在名字上就能表达不同的目的 静态工厂方法 ...
随机推荐
- 以ls命令为实例介绍命令基本格式
登陆Linux命令行会显示一行字符,例如[root@localhost ~ ]#, 其中root表示当前登陆用户,localhost表示主机名,~显示的是当前路径,(-表示当前用户的家目录),#表示 ...
- 格式化用户输入的金额(处理RMB的时候适合)
number_format($str,'2','.',','); function number($k){ if(strpos($k,'.')===false){ $ok = $k.'; }else{ ...
- VSCode用户设置
// 将设置放入此文件中以覆盖默认设置 { //-------- 搜索配置 -------- "search.exclude": { "**/node_modules&q ...
- java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
因为同样的方法在java中没有问题,放到web工程中就出现了问题.网上查到的资料,说只要把mysql-connector-java-5.1.7-bin.jar放入tomcat中的lib文件夹就可以.很 ...
- Android Studio IDE 简单学习和介绍
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- PHP 数组 foreach引用导致的bug
<?php $arr = array('a', 'b', 'c'); foreach($arr as &$v) {} foreach($arr as $v) {} var_dump($a ...
- Docker之功能汇总
Docker-给容器做端口映射 基本的命令是 -P(大写) :Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口基本的命令是 -p(小写) :Docker则可以指定要 ...
- win10-golang环境变量设置
安装go 打开环境变量 添加GOPATH 添加到path 检验 在命令指示符下->go version or go env 配置 在F:\GOPATH下放置C:\go\bin->新建pkg ...
- AndroidImagePicker 的使用
github地址 https://github.com/easonline/AndroidImagePicker 效果图
- 【uTenux实验】中断处理
中断处理是一个比较有意思的东西.uTenux的中断处理包括了处理外部中断.CPU异常等.他是OS中任务无关部分.因此,当中断到来的时候OS会停止任务调度,不会发生任务切换.直到程序从中断中返回. uT ...