一、页内核把物理页作为内存管理的基本单位。尽管处理器的最小可寻址单位通常为字(甚至字节),但是,内存管理单元(MMU,管理内存并把虚拟地址转换为物理地址的硬件)通常以页为单位进行处理。正因为如此,MMU以页(page)大小为单位来管理系统中的页表(这也是页表名的来由)。从虚拟内存的角度来看,页就是最小单位 在后面“可移植性”中我们将会看到,体系结构不同,支持的页大小也不尽相同,还有些体系结构...
待续
一、总体概述时间管理在内核中占有非常重要的地位。相对于事件驱动而言,内核中有大量的函数都是基于时间驱动的 其中有些函数是周期执行的,像对调度程序中的运行队列进行平衡调整或对屏幕进行刷新这样的函数,都需要定期执行,比如说,每秒执行100次 而另外一些函数,比如需要推后执行的磁盘I/O操作等,则需要等待一个相对时间后才运行——比如说,内核会在500ms后再执行某个任务 除了上述两种函...
一、完成变量如果在内核中一个任务需要发出信号通知另一任务发生了某个特定事件,利用完成变量(completion variable)是使两个任务得以同步的简单方法。如果一个任务要执行一些工作时,另 一个任务就会在完成变量上等待。当这个任务完成工作后,会使用完成变量去唤醒在等待的任务。这听起来很像一个信号量,的确如此——思想是一样的。事实上,完成变量仅仅提供了代替信号量的一个简单的解决方法。例
一、互斥体概述直到最近,内核中唯一允许睡眠的锁是信号量。多数用户使用信号量只使用计数1,说白了是把其作为一个互斥的排他锁使用——好比允许睡眠的自旋锁 不幸的是,信号量用途更通用, 没多少使用限制。这点使得信号量适合用于那些较复杂的、未明情况下的互斥访问,比如内核于用户空间复杂的交互行为。但这也意味着简单的锁定而使用信号量并不方便,并且信号量也缺乏强制的规则来行使任何形式的自动调试,即便受限的...
一、自旋锁概述如果每个临界区都能像增加变量这样简单就好了,可惜现实总是残酷的。现实世界里,临界区甚至可以跨越多个函数。举个例子,我们经常会碰到这种情况:先得从一个数据结构中移出 数据,对其进行格式转换和解析,最后再把它加入到另一个数据结构中。整个执行过程必须是原子的,在数据被更新完毕前,不能有其他代码读取这些数据。显然,简单的原子操作对此无能为力,这就需要使用更为复杂的同步方法——锁来提供保护
一、原子操作概述原子操作可以保证指令以原子的方式执行——执行过程不被打断。众所周知,原子原本指的是不可分割的微粒,所以原子操作也就是不能够被分割的指令Linux内核提供的原子接口内核提供了两组原子操作接口——一组针对整数进行操作,另一组针对单独的位进行操作 在Linux支持的所有体系结构上都实现了这两组接口。大多数体系结构会提供支持原子操作的简单算术指令。而有些体系结构确实缺少简单的...
一、下半部机制的选择在各种不同的下半部实现机制之间做出选择是很重要的。在当前的2.6版内核中,有三种可能的选择:软中断、tasklet和工作队列。tasklet基于软中断实现,所以两者很相近。工作队列机 制与它们完全不同,它靠内核线程实现 从设计的角度考虑,软中断提供的执行序列化的保障最少。这就要求软中断处理函数必须格 外小心地采取一些步骤确保共享数据的安全,两个甚至更多相同类别的软中断有可...
一、工作队列概述工作队列(work queue)是另外一种将工作推后执行的形式,它和我们前面讨论的所有其他形式都不相同。工作队列可以把工作推后,交由一个内核线程去执行——这个下半部分总是会在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许重新调度甚至是睡眠 通常,在工作队列和软中断/tasklet中做出选择非常容易。如果推后执行的任务需要睡眠...
一、tasklet概述tasklet是利用软中断实现的一种下半部机制。我们之前提到过,它和进程没有任何关系。tasklet和软中断在本质上很相似,行为表现也相近,但是,它的接口更简单,锁保护也要求较低 选择到底是用软中断还tasklet其实很简单:通常你应该用tasklet。就像我们在前面看到的,软中断的使用者屈指可数。它只在那些执行频率很高和连续性要求很高的情况下才需要使用。而taskle...
一、信号量概述Linux中的信号最是一种睡眠锁。如果有一个任务试图获得一个不可用(已经被占用)的信号量时,信号量会将其推进一个等待队列,然后让其睡眠。这时处理器能重获自由,从而去执行其他代码。当持有的信号量可用(被释放)后,处于等待队列中的那个任务将被唤醒,并获得该信号量 这就比自旋锁提供了更好的处理器利用率,因为没有把时间花费在忙等待上,但是,信号量比自旋锁有更大的开销 可以从信号量的睡...
一、Linux内核同步历史多年之前,在Linux还未支持对称多处理器的时候,避免并发访问数据的方法相对来说比较简单。在单一处理器的时候,只有在中断发生的时候 ,或在内核代码明确地请求重新调度、执行另一个任务的时候,数据才可能被并发访问。 因此早期内核开发工作相比如今要简单许多 但当年的太平日子一去不复返了,从2.0开始,内核就开始支持对称多处理器了,而且从那以后对它的支持不断地加强和完善。支...
一、为什么要下半部在前面的文章中,我们讨论了内核为处理中断而提供的中断处理程序机制。中断处理程序是内核中很有用的(实际上也是必不可少的)部分。但是,由于本身存在一些局限,所以它只能完成整个中断处理流程的上半部分。这些局限包括: 1.中断处理程序以异步方式执行,并且它有可能会打断其他重要代码(甚至包括其他中断处 理程序) 执行。因此,为了避免被打断的代码停止时间过长,中断处理程序应该执行得越...
一、软中断概述现在我们开始讨论下半部的实现——先从软中断开始 软中断使用的比较少。tasklet是下半部更常用的一种形式(但是,由于tasklet是通过软中断实现的,所以我们先来研究软中断) 软中断的代码位于kernel/softirq.c文件中二、软中断的实现struct softirq_action软中断是在编译期间静态分配的。它不像tasklet那样能被动态地注册或注销...
一、中断控制的概述Linux内核提供了一组接口用于操作机器上的中断状态 这些接口为我们提供了能够禁止当前处理器的中断系统,或屏蔽掉整个机器的一条中断线的能力,这些例程都是与体系结构相关的,可以在<asm/system.h>和<asm/irq.h>中找到一般来说,控制中断系统的原因归根结底是需要提供同步: 通过禁止中断,可以确保某个中断处理程序不会抢当前的代码...
一、为什么要引入中断?任何操作系统内核的核心任务,都包含有对连接到计算机上的硬件设备进行有效管理,如硬盘、蓝光碟机、键盘、鼠标、3D 处理器,以及无线电等。而想要管理这些设备,首先要能和它们互通音信才行。众所周知,处理器的速度跟外围硬件设备的速度往往不在一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求,然后专门等待回应的办法,显然差强人意。既然硬件的响应这么慢,那么内核就应该在此期间
一、中断处理程序概述在响应一个特定中断的时候,内核会执行一个函数,该函数叫做中断处理程序(interrupt handler) 或中断服务例程(interrupt service routine, ISR) 产生中断的每个设备都有一个相应的中断处理程序(本质上中断处理程序通常不是和特定设备关联,而是和特定中断关联,也就是说,如果一个设备可以产生多种不同的中断,那么该设备就可以对应多个中断处理...
一、数据结构以及选择前面几篇文章主要介绍了Linux中比较重要的四种数据结构:链表、队列、映射和红黑树要是上述数据结构都不能满足你的需要,内核还实现了一些较少使用的数据结构,也许它们能帮你,比如基树(trie类型)和位图。只有当寻遍所有内核提供的数据结构都不能满足时,你 才需要自己设计数据结构。经常在独立的源文件中实现的一种常见数据结构是散列表。因为散列表无非是一些“桶”和一个散列函数,而且这
一、二叉树一个二叉树是每个节点最多只有两个出边的数二叉树的内容不是本文重点,不再叙述二、二叉搜索树一个二叉搜索树(简称为“BST”)是一个节点有序的二叉树,其顺序通常遵循下列法则:1.根的左分支节点值都小于根节点值2.右分支节点值都大于根节点值3.所有的子树也都是二叉搜索树因此,一个二叉搜索树所有节点必然都有序,且左子节点小于其父节点值,而右子节点大于其父节点值的二叉树。所以,在树中搜索一
一、映射概述一个映射,也称为关联数组 是一个由唯一键组成的集合,而每个键必然关联一个特定的值。这种键到值的关联关系称为映射散列表 散列表是实现映射的一种数据结构 自平衡二叉搜索树虽然可以用散列表实现映射,但映射也可以通过自平衡二叉搜索树存储数据 虽然散列表能提供更好的平均的
一、队列概述任何操作系统内核都少不了一种编程模型:生产者和消费者。在该模式中,生产者创建数据(比如说需要读取的错误信息或者需要处理的网络包),而消费者则反过来,读取消息和处理包,或者以其他方式消费这些数据。实现该模型的最简单的方式无非是使用队列。生产者将数据推进 队列,然后消费者从队列中摘取数据。消费者获取数据的順序和推入队列的顺序一致。也就是说,第一个进队列的数据一定是第一个离开队列的。也正是这
一、链表概述链表是Linux内核中最简单、最普通的数据结构 链表是一种存放和操作可变数量元素(常称为节点)的数据结构。链表和静态数组的不同之处在于,它所包含的元素都是动态创建并插入链表的,在编译时不必知道具体需要创建多少个元素。另外也因为链表中每个元素的创建时间各不相同,所以它们
一、系统调用概述系统调用在用户空间进程和硬件设备之间添加了一个中间层该层主要作用有三个:第一, 为用户空间提供了一种硬件的抽象接口。举例来说,当需要读写文件的时候,应用程序就可以不去管磁盘类型和介质,甚至不用去管文件所在的文件系统到底是哪种类型第二,系统调用保证了系统的稳定和安全。作为硬件设备和应用程序之间的中间人,内核可以基于权限、用户类型和其他一些规则对需要进行的访问进行裁决。
Linux提供了两种实时调度策略:SCHED_FIFO和SCHED_RR 普通的、非实时的调度策略是SCHED__NORMAL 借助调度类的框架,这些实时策略并不被完全公平调度器来管理, 而是被一个特殊的实时调度器管理。具体的实现定义在文件kernel/sched_rt.c中,在接下来的内容中我们将讨论实时调度策略和算法一、
前面一篇文章讨论了CFS调度算法的详细。本文将讨论CFS是如何得以实现的CFS的实现大致分为四个部分:1.时间记账2.进程选择3.调度器入口4.睡眠和唤醒下图是本文要用的一些数据结构一、时间记账所有的调度器都必须对进程运行时间做记账。多数Unix系统,正如我们前面所说,分配一个时间片给每一个进程。那么当每次系统时钟节拍发生时,时间片都会被减少一个节拍周期。当一个进程的时间片被减少到0时,它就会
前面一篇文章抽象的讨论了进程调度原理,在已有的调度原理基础上,本文进一步探讨具有Linux特色的进程调度程序一、调度器类Linux调度器是以模块方式提供的,这样做的目的是允许不同类型的进程可以有针对性地选择调度算法这种模块化结构被称为调度器类(scheduler classes),它允许多种不同的可动态添加的调度算法并存,调度属于自己范畴的进程每个调度器都有一个优先级,基础的调度器
本文是对进程调度的总体概述,下面是几篇详细介绍:Linux调度算法, Linux调度的实现, 上下文切换、用户/内核抢占, 实时调度策略 与调度相关的系统调用 一、进程调度概述前面几篇文章讨论了进程,它在操作系统看来是程序的运行态表现形式。本文及后面几篇文章将讨论进程调度程序,它是确保进程能有效工作的一个内核子系统调度程序负责决定将哪个进程投入运行
一、线程在Linux中的实现线程机制是现代编程技术中常用的一种抽象概念。该机制提供了在同一程序内共享内存地址空间运行的一组线程。这些线程还可以共享打开的文件和其他资源。线程机制支持并发程序设计技术(concurrent programming),在多处理器系统上,它也能保证真正的并行处理(parallelism)
Copyright © 2005-2024 51CTO.COM 版权所有 京ICP证060544号