Linux内核设计与实现
文章平均质量分 64
Linux内核设计与实现所述的内容基于Linux2.6内核,对于爱好Linux学习的朋友来说绝对是不可多得的一本好书,我在阅读的同时记录自己所学,分享自己的学习历程
BruceZhang
计算机专业的一个小学生
展开
-
神奇的大内核锁
Big Kernel Lock(BKL)(大内核锁),是linux内核中使用到的一种锁,它跟普通的锁原理上的一样的:lock_kernel();/* 临界区 */unlock_kernel();但是它又有一些非常诡异的地方。从表面上看:1、BKL是一个全局的锁(注意,是“一个”而不是“一种”),它保护所有使用它来同步的临界区。一旦一个进程获得BKL,进入被它保护的临界区,不但该临界区被上锁,所有被转载 2013-09-04 10:55:46 · 2588 阅读 · 0 评论 -
Linux2.6内核 -- 结构的初始化
Linux 内核中用到了大量的结构体,在编码规范中也给出了结构体初始化的规则,这篇文章中有对其的解释:http://blog.csdn.net/dlutbrucezhang/article/details/10296897,不过,这篇文章中并没有给出实例分析,下面我写了一段测试程序:#include#includestruct test { int test_value1; float原创 2013-08-25 15:06:39 · 2235 阅读 · 0 评论 -
Linux2.6内核 -- 编码风格(3)
9.typedef 内核开发者们强烈反对使用 typedef 语句。他们的理由是: 1> typedef 掩盖了数据的真实类型 2> 由于数据类型隐藏起来了,所以很容易因此而犯错误,比如以传值的方式向栈中推入结构 4> 使用 typedef 往往是因为想要偷懒,例如,可能会定义一个这样的形式: typedef unsigned char uchar 无论如何,尽量少原创 2013-08-25 13:48:05 · 2503 阅读 · 0 评论 -
Linux2.6内核 -- 编码风格(2)
5.每行代码的长度 源代码中要尽可能的保证每行代码长度不超过80个字符,因为这样做可以使代码最适合在标准的 80 * 24 的终端上显示。事实上,并不存在一个广泛接受的标准--如果代码行超过 80 个字符应该折到下一行。 有些开发者会在圆括号内分行,对齐排列函数参数,它看起来就好像下面这样:static void get_new_parrot(const char *name,原创 2013-08-25 10:34:54 · 2354 阅读 · 0 评论 -
Linux2.6内核 -- 编码风格(1)
像所有其他大型软件一样,Linux 制定了一套编码风格,对代码的格式,风格和布局做出了规定。下面我就对 2.6 内核中的代码约定进行介绍。 1.缩进 缩进风格是用制表位(Tab)每次缩进 8 个字符长度。这里指的并不是利用 8 个空格进行缩进。这里的规定很明确,每次缩进通过制表位进行,每个制表位 8 个字符长度。(这里是不是有点奇怪,我们在编程时是不是用 4 个字符缩进就行了?原创 2013-08-25 10:10:57 · 2482 阅读 · 0 评论 -
mmap详解
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式, 因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据: 一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到转载 2013-08-24 17:37:49 · 2756 阅读 · 1 评论 -
Linux2.6内核--对块IO层操作的讨论
当一个块被调入内存时(也就是说,在读入后或等待写出时),它要存储在缓冲区中。每个缓冲区与一个块对应,它相当于是磁盘块在内存中的表示。块包含一个或多个扇区,但大小不能超过一页,所以一页可以容纳一个或多个内存块。由于内核在处理数据时需要一些相关的控制信息(比如块属于哪个设备,块对应于哪个缓冲区),所以,每一个缓冲区都有一个对应的描述符。该描述符用 buffer_head 结构体表示,称作缓冲区头,在文原创 2013-08-23 15:44:33 · 2473 阅读 · 0 评论 -
Linux2.6内核--VFS层中和进程相关的数据结构
系统中的每一个进程都有自己的一组打开的文件,像根文件系统,当前工作目录,安装点等。有三个数据结构将 VFS 层和系统的进程紧密的联系在一起,它们分别是:file_struct,fs_struct 和 namespace 结构体。 file_struct 结构体定义在文件 中。该结构体由进程描述符中的 files 目录项指向。所有的单个进程相关的信息(如打开的文件和文件描述符)都包含在其原创 2013-08-23 14:01:48 · 2583 阅读 · 0 评论 -
Linux2.6内核--内存管理(1)--分页机制
在内核里分配内存可不像在其他地方分配内存那么容易。造成这种局面的因素很多。从根本上讲,是因为内核本身不能像用户空间那样奢侈的使用内存。内核与用户空间不同,它不具备这种能力,它不支持简单便捷的内存分配方式。比如,内核一般不能睡眠。此外,处理内存分配错误对于内核来说也绝非是一件简单的事。正式由于这些限制,再加上内存分配机制不能太复杂,所以在内核中获取内存要比在用户空间复杂的多。 首先,我们讨原创 2013-08-22 14:51:39 · 2509 阅读 · 0 评论 -
Linux2.6内核--内存管理(2)--区
由于硬件的限制,内核不能对所有的页一视同仁。有些页位于内存中的特定物理地址上,所以,不能将其用于一些特别的任务。(关于内存分页机制可以查看:http://blog.csdn.net/dlutbrucezhang/article/details/10181535)由于存在这种限制,所以内核会把页划分为不同的区。内核使用区对具有相似特性的页进行分组。Linux必须处理如下两种由于硬件存在缺陷而引起的内原创 2013-08-22 15:21:38 · 2326 阅读 · 1 评论 -
linux内存屏障浅析
内存屏障主要解决了两个问题:单处理器下的乱序问题和多处理器下的内存同步问题。为什么会乱序现在的CPU一般采用流水线来执行指令。一个指令的执行被分成:取指、译码、访存、执行、写回、等若干个阶段。然后,多条指令可以同时存在于流水线中,同时被执行。指令流水线并不是串行的,并不会因为一个耗时很长的指令在“执行”阶段呆很长时间,而导致后续的指令都卡在“执行”之前的阶段上。相反,流水线是并行的,多个指令可以同转载 2013-08-22 09:34:39 · 2001 阅读 · 0 评论 -
LINUX自旋锁详解2
对于互斥, 旗标是一个有用的工具, 但是它们不是内核提供的唯一这样的工具. 相反, 大部分加锁是由一种称为自旋锁的机制来实现. 不象旗标, 自旋锁可用在不能睡眠的代码中, 例如中断处理. 当正确地使用了, 通常自旋锁提供了比旗标更高的性能. 然而, 它们确实带来对它们用法的一套不同的限制.自旋锁概念上简单. 一个自旋锁是一个互斥设备, 只能有 2 个值:"上锁"和"解锁". 它常常实现为一个整数值转载 2013-08-21 17:04:01 · 1645 阅读 · 0 评论 -
LINUX自旋锁详解
加锁(locking)是一种广泛应用的同步技术。当内核控制路径必须访问共享数据结构或进入临界区时,就需要为自己获取一把“锁”。由锁机制保护的资源非常类似于限制于房间内的资源,当某人进入房间时,就把门锁上。如果内核控制路径希望访问资源,就试图获取钥匙“打开门”。当且仅当资源空闲时,它才能成功。然后,只要它还想使用这个资源,门就依然锁着。当内核控制路径释放了锁时,门就打开,另一个内核控制路径就可以进入转载 2013-08-21 17:02:57 · 6587 阅读 · 0 评论 -
Linux2.6内核--中断下半部实现方法 工作队列
工作队列子系统是一个用于创建内核线程的接口,通过它创建的进程负责执行由内核其他部分排到队列里的任务。它创建的这些内核线程称作工作者线程。工作队列可以让你的驱动程序创建一个专门的工作者线程来处理需要退后的工作。不过,工作队列子系统提供了一个缺省的工作者线程来处理这些工作。因此,工作队列最基本的表现形式,就转变成了一个把需要退后执行的任务交给特定的通用线程的这样一种接口。 缺省的工作者线程叫原创 2013-08-21 13:15:41 · 2327 阅读 · 1 评论 -
Linux2.6--中断机制中的 ksoftirqd
Linux中的中断机制被分为两个部分,回应硬件的中断请求的部分成为上半部(一般都是这样),而真正在做处理工作(耗时工作)的部分成为下半部,实现下半部在Linux2.6内核中存在三种方法:软中断,tasklet和工作队列,如下图所示。 中断下半部处理的时机一般是在中断处理程序返回时。那么现在,我们考虑一种情况,中断下半部程序的执行时又再次触发它自己,这时,内核该怎么去处理这种情况呢?原创 2013-08-21 09:50:47 · 6224 阅读 · 0 评论 -
Linux2.6内核--中断线被关闭的情况
中断系统是现代操作系统中不可获取的一个子系统,它由硬件主动触发并发送到CPU,最后由内核调用中断处理程序处理中断。 那么中断有时候需要关闭,这是为什么呢? 一般分为两种情况:1.内核或程序的某些操作需要关中断2.中断正在执行 下面,我来解释下第二种情况。 下面,首先看一张图: 可以看到,图中红色的中断线被触发,那么这时就需要关闭这条中断线上的所有中原创 2013-08-20 15:05:39 · 2615 阅读 · 0 评论 -
浅析linux内核中的idr机制
idr在linux内核中指的就是整数ID管理机制,从本质上来说,这就是一种将整数ID号和特定指针关联在一起的机制。这个机制最早是在2003年2月加入内核的,当时是作为POSIX定时器的一个补丁。现在,在内核的很多地方都可以找到idr的身影。 idr机制适用在那些需要把某个整数和特定指针关联在一起的地方。举个例子,在I2C总线中,每个设备都有自己的地址,要想在总线上找到特定的设备,就必须转载 2013-08-20 12:26:16 · 10792 阅读 · 0 评论 -
Linux2.6内核中链表的实现
对于一个计算机专业的学生,链表这种数据结构对我们来说再熟悉不过了,毕竟在大学的《数据结构》中就讲解过,相信你也自己实现过,它实现起来可能是这个样子:(这里的例子都来自《Linux内核设计与实现》第三版) 假定我们有一个数据结构来描述犬科动物中的一员struct fox{ unsigned long tail_length; unsigned long weight; bool原创 2013-08-20 10:49:09 · 2232 阅读 · 4 评论 -
linux内核 asmlinkage宏
asmlinkage是个宏,使用它是为了保持参数在stack中。看一下/usr/include/asm/linkage.h里面的定义:#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))其中 __attribute__是关键字,是gcc的C语言扩展。__attribute__机制是GNU C的一大特色,它可以设置函数属性、变量属转载 2013-08-19 16:30:48 · 2881 阅读 · 0 评论 -
Linux系统调用中的参数验证
我们都知道,用户程序可以通过库函数来通知内核执行系统调用,由于是在内核空间中执行,所以,每一个步骤都需要非常小心,因为错误的操作随时可以导致系统崩溃。 系统调用必须仔细检查它们所有的参数是否合法有效。举例来说,与文件IO相关的系统调用必须检查文件描述符是否有效。与进程相关的函数必须检查提供的PID是否有效。必须检查每个参数,保证它们不但合法有效,而且正确。进程不应该让内核去访问那些无权访原创 2013-08-19 13:01:04 · 2375 阅读 · 0 评论 -
Linux2.6--进程抢占和上下文切换
上下文切换,也就是从一个可执行进程切换到另一个可执行进程,由定义在kernel/sched.c中的context_switch()函数负责处理。每当一个新的进程被选出来准备投入运行的时候,schedule()就会调用该函数。它完成了两相基本工作: 1.调用声明在中的switch_mm(),该函数负责把虚拟内存从上一个进程映射切换到新的进程中去,其实就是切换到另一个进程的地址空间中,请看下原创 2013-08-19 10:07:59 · 3041 阅读 · 1 评论 -
读《Linux内核设计与实现》我想到了这些书
从题目中可以看到,这篇文章是以我读《Linux内核设计与实现》而想到的其他我读过的书,所以,这篇文章的主要支撑点是《Linux内核》。 开始读这本书已经是很久以前的事了,不过,由于时间和精力原因,没有认真的分析和深入研究这本书所涉及的诸多内容,现在想来,仍旧很是遗憾,直到最近,再次把这本书拿过来阅读,才勉强可以说是对书中的知识点有了一定的了解,我说的这种了解,远达不到精通的地步,可能略懂原创 2013-08-19 08:59:49 · 15445 阅读 · 37 评论 -
linux下字节对齐
一,内存地址对齐的概念 计算机内存中排列、访问数据的一种方式,包含基本数据对齐和结构体数据对齐。 32位系统中,数据总线宽度为32,每次能够读取4字节数据。地址总线为32,最大寻址空间为4GB。但是由于最低位A[0]~A[1]是不用于寻址的,因此只能访问4的倍数的地址空间,但是寻址空间还是2^30*字长=4GB。 因此内存中除了结构体中成员变量之外的基本类型的开始的手地址最低两位都是0。转载 2013-08-15 16:11:19 · 3920 阅读 · 0 评论 -
Linux/Unix--设备类型
在Linux以及所有的Unix系统中,设备被分为以下三种类型: 块设备 字符设备 网络设备 块设备通常写为 blkdev ,它是可以寻址的,寻址以块为单位,块大小随设备的不同而不同;块设备通常支持重定位操作,也就是对数据的随机访问。块设备的例子有硬盘,蓝光光碟,还有如Flash这样的存储设备。块设备是通过称为“块设备节点”的特殊文件来访问的,并且通常被挂载原创 2013-08-15 13:22:34 · 3324 阅读 · 0 评论 -
Linux内存映射--mmap函数
Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明:头文件:原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offsize);返回值: 成功则返回映射区起始地址, 失转载 2013-08-14 17:12:07 · 3819 阅读 · 0 评论 -
Linux内核线程
内核线程是直接由内核本身启动的进程。内核线程实际上是将内核函数委托给独立的进程,与系统中其他进程“并行”执行(实际上,也并行于内核自身的执行),内核线程经常被称为内核“守护进程”。它们主要用于执行下列任务:l 周期性地将修改的内存页与页来源块设备同步。l 如果内存页很少使用,则写入交换区。l 管理延时动作l 实现文件系统的事务日志。 内核线程主要有两种类型:1. 线程启动后一直等待,直至内转载 2013-08-14 15:15:56 · 1681 阅读 · 0 评论 -
Linux2.6--Linus电梯
内核为了处理来自IO层的请求,需要进行相应的优化,因为当请求很多时,且请求的块又都几种在一块,那么如果按照顺序处理这些请求无疑是很大的时间开销,所以,我们需要寻求方法来处理这种情况(当然,不只是这一种情况),这篇文章介绍的就是Linux中经典的IO调度程序--Linus电梯,这个是以Linux的发明者Linus自己的名字命名的。在2.4版的内核中,Linus电梯是默认的IO调度程序。虽然在后来的2原创 2013-08-14 13:31:46 · 2322 阅读 · 0 评论 -
Linux2.6--虚拟文件系统
虚拟文件系统(有时也称作虚拟文件交换,更常见的是简称做VFS)作为内核子系统,为用户空间程序提供了文件和文件系统相关的接口.系统中的所有文件系统不但依赖VFS共存,而且也依赖VFS系统协同工作.通过虚拟文件系统,程序可以利用标准的UNIX系统调用对不同的文件系统,甚至不同的介质上的文件系统进行读写操作,如下如图所示: 这幅图的含义是: VFS执行的动作:使用CP(1)命令从ex原创 2013-08-14 10:10:33 · 2183 阅读 · 0 评论 -
Linux2.6中的Slab层
还记得一个进程创建的时候是什么给它分配的“进程描述符”吗?没错,是slab分配器,那么,这个slab分配器是个什么东西呢? 分配和释放数据结构是所有内核中最普遍的操作之一。为了便于结构的频繁分配和回收,编程人员常常会用到空闲链表。空闲链表中包含可供使用的,已经分配好的数据结构块。当代码需要一个新的数据结构实例时,就可以从空闲链表中抓取一个,而不需要再去执行一些分配内存的代码,这样不仅高效原创 2013-08-12 16:23:14 · 2200 阅读 · 0 评论 -
内存管理单元--MMU
现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要处理器中的MMU(Memory Management Unit,内存管理单元)提供支持,本节简要介绍MMU的作用。首先引入两个概念,虚拟地址和物理地址。如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收转载 2013-08-12 15:19:54 · 2852 阅读 · 1 评论 -
直接内存访问(DMA)
1. 什么是DMA直接内存访问是一种硬件机制,它允许外围设备和主内存之间直接传输它们的I/O数据,而不需要系统处理器的参与。使用这种机制可以大大提高与设备通信的吞吐量。 2. DMA数据传输有两种方式引发数据传输:第一种情况:软件对数据的请求1. 当进程调用read,驱动程序函数分配一个DMA缓冲区,并让硬件将数据传输到这个缓冲区中。进程处于睡眠状态。2. 硬件将数据写入到DMA缓冲区中,当写入完转载 2013-08-12 14:48:22 · 2287 阅读 · 0 评论 -
对 jiffies 溢出、回绕及 time_after 宏的理解
原文如下:关于jiffies变量: 全局变量jiffies用来记录自启动以来产生的节拍的总数。系统启动时会将该变量初始化为0,此后,每当时钟中断产生时就会增加该变量的值。jiffies和另外一个变量息息相关:HZ。HZ是每秒系统产生的时钟中断次数,所以jiffies每秒增加的值也就是HZ;在x86体系结构中,内核版本在2.4以前的值为100,在2.6内核中被定义为1000。 jiffie转载 2013-08-12 11:11:20 · 5554 阅读 · 1 评论 -
Linux内核--异常和中断的区别
相信大家都知道非常著名的两个名词:异常和中断,不过,你真的理解这两个名词在说什么吗?它们之间有什么区别呢? 1.中断 大家都知道,当我们在敲击键盘的同时就会产生中断,当硬盘读写完数据之后也会产生中断,所以,我们需要知道,中断是由硬件设备产生的,而它们从物理上说就是电信号,之后,它们通过中断控制器发送给CPU,接着CPU判断收到的中断来自于哪个硬件设备(这定义在内核中),最后,由原创 2013-08-09 15:38:15 · 4415 阅读 · 0 评论 -
linux2.6内核链表
一、 链表数据结构简介 链表是一种常用的组织有序数据的数据结构,它通过指针将一系列数据节点连接成一条数据链,是线性表的一种重要实现方式。相对于数组,链表具有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配空间,可以高效地在链表中的任意位置实时插入或删除数据。链表的开销主要是访问的顺序性和组织链的空间损失。 通常链表数据结构至少应包含两个域:数据域和指针域转载 2013-08-09 13:09:38 · 1452 阅读 · 1 评论 -
机制与策略
Unix/Linux的接口设计有一句通用的格言“提供机制而不是策略”。区别对待机制(mechanism)和策略(policy)是Unix设计中的一大亮点。大部分的编程问题都可以被切割成两个部分:“需要提供什么功能”(机制)和“怎样实现这些功能”(策略)。如果由程序中的独立部分分别负责机制和策略的实现,那么开发软件就更容易,也更容易适应不同的需求。 开源-展现在我们面前的是数以千计的代码,在那一行行转载 2013-08-07 22:51:59 · 3633 阅读 · 0 评论 -
Linux系统调用的实现机制分析
【摘要】本文介绍了系统调用的一些实现细节。首先分析了系统调用的意义,它们与库函数和应用程序接口有怎样的关系。然后,我们考察了内核如何实现系统调用,以及执行系统调用的连锁反应:陷入内核,传递系统调用号和参数,执行正确的系统调用函数,并把返回值带回用户空间。最后讨论了如何增加系统调用,并提供了从用户空间访问系统调用的简单例子。1 系统调用意义linux内核中设置了一组用于实现系统功能的子程转载 2013-08-07 19:23:29 · 3782 阅读 · 1 评论 -
Linux2.6 --系统调用处理程序
用户空间的程序无法直接执行内核代码。它们不能直接调用内核空间中的函数,因为内核驻留在受保护的地址空间上。如果进程可以直接在内核的地址空间上读写的话,系统的安全性和稳定性将不复存在。 所以,应用程序应该以某种方式通知系统,告诉内核自己需要执行一个系统调用,希望系统切换到内核态,这样内核就可以代表应用程序在内核空间执行系统调用。 通知内核的机制是靠软中断实现的:通过引发一个异常来促原创 2013-08-07 18:57:24 · 1841 阅读 · 0 评论 -
Linux2.6内核--抢占
【摘要】本文首先介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核(Preemptive Kernel)的区别。接着分析Linux下有两种抢占:用户态抢占(User Preemption)、内核态抢占(Kernel Preemption)。然后分析了在内核态下:如何判断能否抢占内核(什么是可抢占的条件);何时触发重新调度(何时设置可抢占条件);抢占发生的时机(何时检查可抢转载 2013-08-07 15:40:50 · 1739 阅读 · 0 评论 -
linux内核cfs浅析
linux调度器的一般原理请参阅《linux进程调度浅析》。之前的调度器cfs之前的linux调度器一般使用用户设定的静态优先级,加上对于进程交互性的判断来生成动态优先级,再根据动态优先级决定进程被调度的顺序,以及调度后可以运行的时间片。反过来,随着进程的运行,内核可能发现其交互性发生改变,从而调整其动态优先级(奖励睡眠多的交互式进程、惩罚睡眠少的批处理进程)。cfs原理cfs定义了一种新的模型,转载 2013-08-07 04:28:45 · 1971 阅读 · 0 评论 -
Linux内核2.6的进程调度
Linux是多任务抢占操作系统,多任务就是指多个进程间通过分时切换来并发执行。非抢占的系统是对每个进程而言,除非时间片用完或主动放弃否则不会被剥夺CPU,主动放弃包括调用一些调度的系统调用(比如sched_yield)或者调用IO等阻塞操作。抢占式系统表示即使当前进程没有用完时间片,也没有主动放弃CPU,如果调度系统发现有更高动态优先级的进程,则强制剥夺当前进程的CPU,选择更高动态优先级的进程执转载 2013-08-06 22:08:45 · 1952 阅读 · 0 评论