
Linux(内核剖析)
本专栏介绍Linux内核的基础概念,包括但不限于进程管理、进程调度、时间管理、内存管理、VFS等技术。阅读完本专栏之后你可以对Linux内核有一个系统性地深刻认知(持续更新)
董哥的黑板报
90后程序员!
展开
-
Linux(内核剖析):01---Unix历史、Linux简介
一、Unix历史U n ix虽然已经使用了40年,但计算机科学家仍然认为它是现存操作系统中最强大和最优秀的系统。从1969年诞生以来,由Dennis R itchie和Ken Thompson的灵感火花点亮的这个Unix 产物已经成为一种传奇,它历经了时间的考验依然声名不坠贝尔实验室Unix是从贝尔试验室的一个失败的多用户操作系统Multics中涅槃而生的。M ultics项目被终止后...原创 2019-12-22 22:14:37 · 2053 阅读 · 0 评论 -
Linux(内核剖析):02---Linux内核源码下载并编译Linux内核、内核开发的特点
一、获取内核源码Linux内核官网:https://www.kernel.org/ Linux内核网站下载:https://mirrors.edge.kernel.org/pub/linux/kernel/ 这些网站可以随时获取当前版本的Linux源代码,可以是完整地压缩形式(使用tar命令创建的一个压缩文件),也可以是增量补丁形式使用GitLinus和他领导的内核开发者们开始使用...原创 2019-12-22 22:30:30 · 1059 阅读 · 0 评论 -
Linux(内核剖析):03---进程总体概述
前言本文是对进程的总体概述,具体细节会在后面几篇文章分别介绍 进程描述符task_struct介绍,见文章:https://blog.youkuaiyun.com/qq_41453285/article/details/103743235 进程的创建与终结介绍,见文章:https://blog.youkuaiyun.com/qq_41453285/article/details/103743246 线程介绍,见...原创 2019-12-28 12:23:41 · 1046 阅读 · 0 评论 -
Linux(内核剖析):04---进程之struct task_struct进程描述符、任务结构介绍
一、进程描述符(structtask_struct)、任务结构任务队列内核把进程的列表存放在叫做任务队列(task list) 的双向循环链表中。链表中的每一 项都是类型为task_struct 备注:有些操作系统会把任务队列称为任务数组。但是Linux实现时使用的是队列而不是静态数组,所以称为任务队列进程描述符(struct task_struct)task_stru...原创 2019-12-28 19:31:42 · 5386 阅读 · 0 评论 -
Linux(内核剖析):05---进程之进程的创建与终结(fork、vfork、exit)
一、进程创建概述其他的操作系统产生进程的机制:许多其他的操作系统都提供了产生(spawn) 进程的机制,首先在新的地址空间里创建进程,读入可执行文件,最后开始执行 Unix创建进程的机制:它把上述步骤分解到两个单独的函数中去执行:fork()、exec() 1.首先,fork()通过拷贝当前进程创建一个子进程。子进程与父进程的区别仅仅在于PID (每个进程唯一) 、PPID (父进程的进程...原创 2019-12-28 23:27:54 · 1145 阅读 · 0 评论 -
Linux(内核剖析):06---进程之线程的实现
一、线程在Linux中的实现线程机制是现代编程技术中常用的一种抽象概念。该机制提供了在同一程序内共享内存地址空间运行的一组线程。这些线程还可以共享打开的文件和其他资源。线程机制支持并发程序设计技术(concurrent programming),在多处理器系统上,它也能保证真正的并行处理(parallelism) Linux实现线程的机制非常独特。 从内核的角度来说,它并没有线程这个概念。...原创 2019-12-29 15:24:31 · 1005 阅读 · 1 评论 -
Linux(内核剖析):07---进程调度总体概述(多任务系统、策略、时间片)
本文是对进程调度的总体概述,下面是几篇详细介绍: Linux调度算法,见文章:https://blog.youkuaiyun.com/qq_41453285/article/details/103757512 Linux调度的实现,见文章:https://blog.youkuaiyun.com/qq_41453285/article/details/103757524 上下文切换、用户/内核抢占,见文章:htt...原创 2019-12-29 20:49:31 · 1344 阅读 · 3 评论 -
Linux(内核剖析):08---进程调度之Linux调度算法(调度器类、公平调度(CFS))
前面一篇文章(https://blog.youkuaiyun.com/qq_41453285/article/details/103754148)抽象的讨论了进程调度原理,在已有的调度原理基础上,本文进一步探讨具有Linux特色的进程调度程序一、调度器类Linux调度器是以模块方式提供的,这样做的目的是允许不同类型的进程可以有针对性地选择调度算法 这种模块化结构被称为调度器类(scheduler cl...原创 2019-12-30 13:51:24 · 1603 阅读 · 5 评论 -
Linux(内核剖析):09---进程调度之Linux调度的实现(struct sched_entity、schedule())
前面一篇文章(https://blog.youkuaiyun.com/qq_41453285/article/details/103757512)讨论了CFS调度算法的详细。本文将讨论CFS是如何得以实现的 CFS的实现大致分为四个部分: 1.时间记账 2.进程选择 3.调度器入口 4.睡眠和唤醒 下图是本文要用的一些数据结构一、时间记账所有的调度器都必须对进程运行时间做记账。...原创 2020-01-01 14:43:50 · 1785 阅读 · 2 评论 -
Linux(内核剖析):10---进程调度之上下文切换、用户/内核抢占(context_switch()、need_resched标志、preempt_count计数器)
一、上下文切换上下文切换:也就是从一个可执行进程切换到另一个可执行进程context_switch()函数由context_switch()函数负责处理。每当一个新的进程被选出来准备投入运行的时候,schedule()就会调用该函数 它完成了两项基本的工作: 1.调用声明在<asm/mmu_context.h>中的switch_mm()。该函数负责把虚拟内存从上一个进程...原创 2020-01-01 15:29:37 · 1296 阅读 · 0 评论 -
Linux(内核剖析):11---进程调度之实时调度策略(SCHED_FIFO、SCHED_RR、MAX_RT_PRIO实时优先级)
Linux提供了两种实时调度策略:SCHED_FIFO和SCHED_RR 普通的、非实时的调度策略是SCHED__NORMAL 借助调度类的框架,这些实时策略并不被完全公平调度器来管理, 而是被一个特殊的实时调度器管理。具体的实现定义在文件kernel/sched_rt.c中,在接下来的内容中我们将讨论实时调度策略和算法一、SCHED_FIFOSCHED_FIFO实现了一种简单的、先入先...原创 2020-01-01 15:52:45 · 3868 阅读 · 1 评论 -
Linux(内核剖析):12---进程调度之与调度相关的系统调用
Linux提供了一个系统调用族,用于管理与调度程序相关的参数。这些系统调用可以用来操作和处理进程优先级、调度策略及处理器绑定,同时还提供了显式地将处理器交给其他进程的机制 下标列举了这些系统调用,我们会在后面介绍系统调用的时候介绍这些函数一、与调度策略和优先级相关的系统调用sched_setscheduler()、sched_getscheduler(): 分別用于设置和获取进程的...原创 2020-01-01 16:16:55 · 1478 阅读 · 1 评论 -
Linux(内核剖析):13---系统调用的实现与解析
一、系统调用概述系统调用在用户空间进程和硬件设备之间添加了一个中间层 该层主要作用有三个: 第一, 为用户空间提供了一种硬件的抽象接口。举例来说,当需要读写文件的时候,应用程序就可以不去管磁盘类型和介质,甚至不用去管文件所在的文件系统到底是哪种类型 第二,系统调用保证了系统的稳定和安全。作为硬件设备和应用程序之间的中间人,内核可以基于权限、用户类型和其他一些规则对需要进行的访问进行裁决...原创 2020-01-02 16:33:01 · 1647 阅读 · 0 评论 -
Linux(内核剖析):14---内核数据结构之链表(struct list_head)
一、链表概述链表是Linux内核中最简单、最普通的数据结构 链表是一种存放和操作可变数量元素(常称为节点)的数据结构。链表和静态数组的不同之处在于,它所包含的元素都是动态创建并插入链表的,在编译时不必知道具体需要创建多少个元素。另外也因为链表中每个元素的创建时间各不相同,所以它们在内存中无须占用连续内存区。正是因为元素不连续地存放,所以各元素需要通过某种方式被连接在一起。于是每个元素都包含一...原创 2020-01-03 23:08:06 · 987 阅读 · 0 评论 -
Linux(内核剖析):15---内核数据结构之队列(struct kfifo)
一、队列概述任何操作系统内核都少不了一种编程模型:生产者和消费者。在该模式中,生产者创建数据(比如说需要读取的错误信息或者需要处理的网络包),而消费者则反过来,读取消息和处理包,或者以其他方式消费这些数据。实现该模型的最简单的方式无非是使用队列。生产者将数据推进 队列,然后消费者从队列中摘取数据。消费者获取数据的順序和推入队列的顺序一致。也就是说,第一个进队列的数据一定是第一个离开队列的。也正...原创 2020-01-05 14:57:15 · 1284 阅读 · 0 评论 -
Linux(内核剖析):16---内核数据结构之映射(struct idr)
一、映射概述一个映射,也称为关联数组 是一个由唯一键组成的集合,而每个键必然关联一个特定的值。这种键到值的关联关系称为映射散列表 散列表是实现映射的一种数据结构 自平衡二叉搜索树虽然可以用散列表实现映射,但映射也可以通过自平衡二叉搜索树存储数据 虽然散列表能提供更好的平均的渐进复杂度,但是二叉搜索树在最坏情况下能有更好的表现(即对数复杂性相比线型复杂性) 二叉搜索树同时...原创 2020-01-05 17:30:40 · 2232 阅读 · 1 评论 -
Linux(内核剖析):17---内核数据结构之二叉树(struct rb_root、struct rb_node)
一、二叉树一个二叉树是每个节点最多只有两个出边的数 二叉树的内容不是本文重点,不再叙述二、二叉搜索树一个二叉搜索树(简称为“BST”)是一个节点有序的二叉树,其顺序通常遵循下列法则: 1.根的左分支节点值都小于根节点值 2.右分支节点值都大于根节点值 3.所有的子树也都是二叉搜索树 因此,一个二叉搜索树所有节点必然都有序,且左子节点小于其父节点值,而右子节点大于其父节...原创 2020-01-11 15:53:42 · 2415 阅读 · 0 评论 -
Linux(内核剖析):18---内核数据结构总结(数据结构选择与算法复杂度分析)
一、数据结构以及选择前面几篇文章主要介绍了Linux中比较重要的四种数据结构:链表、队列、映射和红黑树 要是上述数据结构都不能满足你的需要,内核还实现了一些较少使用的数据结构,也许它们能帮你,比如基树(trie类型)和位图。只有当寻遍所有内核提供的数据结构都不能满足时,你 才需要自己设计数据结构。经常在独立的源文件中实现的一种常见数据结构是散列表。因为散列表无非是一些“桶”和一个散列函数,而...原创 2020-01-11 16:21:18 · 884 阅读 · 0 评论 -
Linux(内核剖析):19---中断总体概述
一、为什么要引入中断?任何操作系统内核的核心任务,都包含有对连接到计算机上的硬件设备进行有效管理,如硬盘、蓝光碟机、键盘、鼠标、3D 处理器,以及无线电等。而想要管理这些设备,首先要能和它们互通音信才行。众所周知,处理器的速度跟外围硬件设备的速度往往不在一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求,然后专门等待回应的办法,显然差强人意。既然硬件的响应这么慢,那么内核就应该在此期间...原创 2020-01-12 13:39:37 · 5012 阅读 · 0 评论 -
Linux(内核剖析):20---中断之中断处理程序(request_irq、free_irq)
一、中断处理程序概述在响应一个特定中断的时候,内核会执行一个函数,该函数叫做中断处理程序(interrupt handler) 或中断服务例程(interrupt service routine, ISR) 产生中断的每个设备都有一个相应的中断处理程序(本质上中断处理程序通常不是和特定设备关联,而是和特定中断关联,也就是说,如果一个设备可以产生多种不同的中断,那么该设备就可以对应多个中断处理...原创 2020-01-12 16:45:56 · 2960 阅读 · 0 评论 -
Linux(内核剖析):21---中断之中断上下文、中断处理机制的实现、/proc/interrupts
一、中断上下文当执行一个中断处理程序时,内核处于中断上下文(interrput context) 中 让我们先回忆一下进程上下文。进程上下文是一种内核所处的操作模式,此时内核代表进程执行——例如, 执行系统调用或运行内核线程。在进程上下文中,可以通过current宏关联当前进程。此外,为进程是以进程上下文的形式连接到内核中的,因此,进程上下文可以睡眠,也可以调用调度程序 不可调用睡眠函数:...原创 2020-01-12 18:25:10 · 3989 阅读 · 0 评论 -
Linux(内核剖析):22---中断之中断控制接口(禁止/激活/屏蔽中断)
一、中断控制的概述Linux内核提供了一组接口用于操作机器上的中断状态 这些接口为我们提供了能够禁止当前处理器的中断系统,或屏蔽掉整个机器的一条中断线的能力,这些例程都是与体系结构相关的,可以在<asm/system.h>和<asm/irq.h>中找到一般来说,控制中断系统的原因归根结底是需要提供同步: 通过禁止中断,可以确保某个中断处理程序不会抢当前的代码...原创 2020-01-13 22:43:35 · 2017 阅读 · 0 评论 -
Linux(内核剖析):23---中断下半部之(下半部总体概述)
一、为什么要下半部在前面的文章中,我们讨论了内核为处理中断而提供的中断处理程序机制。中断处理程序是内核中很有用的(实际上也是必不可少的)部分。但是,由于本身存在一些局限,所以它只能完成整个中断处理流程的上半部分。这些局限包括: 1.中断处理程序以异步方式执行,并且它有可能会打断其他重要代码(甚至包括其他中断处 理程序) 执行。因此,为了避免被打断的代码停止时间过长,中断处理程序应该执行得越...原创 2020-01-15 22:15:48 · 1097 阅读 · 0 评论 -
Linux(内核剖析):24---中断下半部之(软中断机制(struct softirq_action、softirq_vec))
一、软中断概述现在我们开始讨论下半部的实现——先从软中断开始 软中断使用的比较少。tasklet是下半部更常用的一种形式(但是,由于tasklet是通过软中断实现的,所以我们先来研究软中断) 软中断的代码位于kernel/softirq.c文件中二、软中断的实现struct softirq_action软中断是在编译期间静态分配的。它不像tasklet那样能被动态地注册或注销...原创 2020-01-16 11:18:01 · 1349 阅读 · 0 评论 -
Linux(内核剖析):25---中断下半部之(tasklet机制(struct tasklet_struct)、BH机制)
一、tasklet概述tasklet是利用软中断实现的一种下半部机制。我们之前提到过,它和进程没有任何关系。tasklet和软中断在本质上很相似,行为表现也相近,但是,它的接口更简单,锁保护也要求较低 选择到底是用软中断还tasklet其实很简单:通常你应该用tasklet。就像我们在前面看到的,软中断的使用者屈指可数。它只在那些执行频率很高和连续性要求很高的情况下才需要使用。而taskle...原创 2020-01-16 14:30:16 · 2156 阅读 · 0 评论 -
Linux(内核剖析):26---中断下半部之(工作队列机制(workqueue_struct、cpu_workqueue_struct))
一、工作队列概述工作队列(work queue)是另外一种将工作推后执行的形式,它和我们前面讨论的所有其他形式都不相同。工作队列可以把工作推后,交由一个内核线程去执行——这个下半部分总是会在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许重新调度甚至是睡眠 通常,在工作队列和软中断/tasklet中做出选择非常容易。如果推后执行的任务需要睡眠...原创 2020-01-17 20:58:26 · 1541 阅读 · 0 评论 -
Linux(内核剖析):27---中断下半部之(下半部机制的选择、在下半部之间加锁、禁止下半部(local_bh_disable、local_bh_enable))
一、下半部机制的选择在各种不同的下半部实现机制之间做出选择是很重要的。在当前的2.6版内核中,有三种可能的选择:软中断、tasklet和工作队列。tasklet基于软中断实现,所以两者很相近。工作队列机 制与它们完全不同,它靠内核线程实现 从设计的角度考虑,软中断提供的执行序列化的保障最少。这就要求软中断处理函数必须格 外小心地采取一些步骤确保共享数据的安全,两个甚至更多相同类别的软中断有可...原创 2020-01-17 21:12:17 · 4635 阅读 · 0 评论 -
Linux(内核剖析):28---内核同步之(临界区、竞争条件、同步、锁、常见的内核并发、SMNP和UP配置选项、锁的争用和扩展性(锁粒度))
一、Linux内核同步历史多年之前,在Linux还未支持对称多处理器的时候,避免并发访问数据的方法相对来说比较简单。在单一处理器的时候,只有在中断发生的时候 ,或在内核代码明确地请求重新调度、执行另一个任务的时候,数据才可能被并发访问。 因此早期内核开发工作相比如今要简单许多 但当年的太平日子一去不复返了,从2.0开始,内核就开始支持对称多处理器了,而且从那以后对它的支持不断地加强和完善。支...原创 2020-01-23 09:00:04 · 1522 阅读 · 0 评论 -
Linux(内核剖析):29---内核同步之(原子操作(原子整数操作(atomic_t、atomic64_t)、原子位操作))
一、原子操作概述原子操作可以保证指令以原子的方式执行——执行过程不被打断。众所周知,原子原本指的是不可分割的微粒,所以原子操作也就是不能够被分割的指令Linux内核提供的原子接口内核提供了两组原子操作接口——一组针对整数进行操作,另一组针对单独的位进行操作 在Linux支持的所有体系结构上都实现了这两组接口。大多数体系结构会提供支持原子操作的简单算术指令。而有些体系结构确实缺少简单的...原创 2020-01-25 14:54:42 · 6121 阅读 · 5 评论 -
Linux(内核剖析):30---内核同步之(自旋锁(spin lock)、读-写自旋锁(spin wrlock))
一、自旋锁概述如果每个临界区都能像增加变量这样简单就好了,可惜现实总是残酷的。现实世界里,临界区甚至可以跨越多个函数。举个例子,我们经常会碰到这种情况:先得从一个数据结构中移出 数据,对其进行格式转换和解析,最后再把它加入到另一个数据结构中。整个执行过程必须是原子的,在数据被更新完毕前,不能有其他代码读取这些数据。显然,简单的原子操作对此无能为力,这就需要使用更为复杂的同步方法——锁来提供保护...原创 2020-01-27 12:40:12 · 2486 阅读 · 0 评论 -
Linux(内核剖析):31---内核同步之(信号量(semaphore)、读写信号量(rw_semaphore))
一、信号量概述Linux中的信号最是一种睡眠锁。如果有一个任务试图获得一个不可用(已经被占用)的信号量时,信号量会将其推进一个等待队列,然后让其睡眠。这时处理器能重获自由,从而去执行其他代码。当持有的信号量可用(被释放)后,处于等待队列中的那个任务将被唤醒,并获得该信号量 这就比自旋锁提供了更好的处理器利用率,因为没有把时间花费在忙等待上,但是,信号量比自旋锁有更大的开销 可以从信号量的睡...原创 2020-01-28 16:17:55 · 1021 阅读 · 0 评论 -
Linux(内核剖析):32---内核同步之(互斥体(mutex))
一、互斥体概述直到最近,内核中唯一允许睡眠的锁是信号量。多数用户使用信号量只使用计数1,说白了是把其作为一个互斥的排他锁使用——好比允许睡眠的自旋锁 不幸的是,信号量用途更通用, 没多少使用限制。这点使得信号量适合用于那些较复杂的、未明情况下的互斥访问,比如内核于用户空间复杂的交互行为。但这也意味着简单的锁定而使用信号量并不方便,并且信号量也缺乏强制的规则来行使任何形式的自动调试,即便受限的...原创 2020-01-28 19:38:23 · 1018 阅读 · 0 评论 -
Linux(内核剖析):33---内核同步之(完成变量(completion)、大内核锁(BLK)、顺序所(seqlock)、禁止抢占、顺序和屏障(barriers))
一、完成变量如果在内核中一个任务需要发出信号通知另一任务发生了某个特定事件,利用完成变量(completion variable)是使两个任务得以同步的简单方法。如果一个任务要执行一些工作时,另 一个任务就会在完成变量上等待。当这个任务完成工作后,会使用完成变量去唤醒在等待的任务。这听起来很像一个信号量,的确如此——思想是一样的。事实上,完成变量仅仅提供了代替信号量的一个简单的解决方法。例如,...原创 2020-01-29 15:51:55 · 1738 阅读 · 1 评论 -
Linux(内核剖析):34---定时器和时间管理总体概述、内核中的时间概念
一、总体概述时间管理在内核中占有非常重要的地位。相对于事件驱动而言,内核中有大量的函数都是基于时间驱动的 其中有些函数是周期执行的,像对调度程序中的运行队列进行平衡调整或对屏幕进行刷新这样的函数,都需要定期执行,比如说,每秒执行100次 而另外一些函数,比如需要推后执行的磁盘I/O操作等,则需要等待一个相对时间后才运行——比如说,内核会在500ms后再执行某个任务 除了上述两种函...原创 2020-02-04 21:42:58 · 920 阅读 · 0 评论 -
Linux(内核剖析):35---时间管理之(节拍率HZ)
待续原创 2020-02-18 13:00:26 · 1288 阅读 · 1 评论 -
Linux(内核剖析):36---时间管理之(硬时钟和定时器、时钟处理中断程序、实际时间)
待续原创 2020-02-18 13:06:33 · 789 阅读 · 0 评论 -
Linux(内核剖析):37---时间管理之(延迟执行)
待续原创 2020-02-18 13:07:51 · 797 阅读 · 0 评论 -
Linux(内核剖析):38---内存管理之(页(struct page)、区(struct zone))
一、页内核把物理页作为内存管理的基本单位。尽管处理器的最小可寻址单位通常为字(甚至字节),但是,内存管理单元(MMU,管理内存并把虚拟地址转换为物理地址的硬件)通常以页为单位进行处理。正因为如此,MMU以页(page)大小为单位来管理系统中的页表(这也是页表名的来由)。从虚拟内存的角度来看,页就是最小单位 在后面“可移植性”中我们将会看到,体系结构不同,支持的页大小也不尽相同,还有些体系结构...原创 2020-02-24 15:30:29 · 3786 阅读 · 0 评论