下载

1下载券

加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 Linux_学习笔记_-_中断

Linux_学习笔记_-_中断.doc

Linux_学习笔记_-_中断

风雨
2010-10-02 0人阅读 举报 0 0 暂无简介

简介:本文档为《Linux_学习笔记_-_中断doc》,可适用于IT/计算机领域

HuaweiTechnologiesCoLinux中断​ 介绍我们知道处理器的处理速度比硬件来说要快上N个数量级那么由处理器向硬件发出请求并等待回应的办法显然是不可取的在这期间处理器浪费了大量的时间。这些时间应该被用来处理其他的事务。轮询可能是解决办法之一但显然这样的办法也会让处理器做大量的无用功。最好的办法就是让硬件在需要的时候才向内核发出信号然后处理器去响应硬件的请求。这就是中断机制。​ 什么是中断当硬件需要和处理器通信时会产生一个电信号(即中断信号)并发往处理器处理器收到后会告诉OS然后由OS进行后续处理。每一种硬件设备都有其专门的中断值OS得以通过这个来进行区分到底是哪个设备发生了中断。这些中断值又被称为中断请求(IRQ)当然有的IRQ是动态分配的。其实OS关注的并不是某个设备一定要产生某个特定的IRQ而是一个特定的IRQ要和一个特定的设备有映射的关系而且OS需要知道这种关系。这就表明即便是IRQ在多个设备之间进行共享也是可以的只要OS能够知道这些映射关系并且能够有办法区分某一个时刻产生中断的设备是哪一个即可。​ 中断处理程序中断处理程序顾名思义自然就是发生中断时需要调用的处理函数。特点:1、不是每设备一个处理程序而是每中断一个处理程序。2、运行于特殊的上下文中:中断上下文3、一般的中断处理程序都会关中断考虑到中断随时都有可能发生处理程序应当尽可能的高效4、一般中断处理程序都是要和硬件打交道的​ 中断上下文​ 回忆进程上下文、​ 对内核而言处于进程上下文表明内核处于这样一种模式:进程在执行(系统调用或者运行内核线程)、​ 可以通过current宏关联当前进程、​ 进程以进程上下文的形式关联内核使得在进程上下文中可以睡眠也可以调用调度程序。​ 中断上下文中断上下文则和进程上下文几乎完全相反:和进程无关、和current宏无关不能睡眠、不能调用会导致睡眠的函数。另外处于中断上下文的代码应当迅速、简洁尽量把工作放到下半部中去完成。关于中断使用的堆栈:的内核之前中断没有自己的堆栈而是与被中断的内核线程共享该线程的堆栈(页)。之后内核增加了一个选项:每个内核线程只提供一页内存这减轻了内存的压力也同时促使中断被分离了出来:每处理器一页称为中断栈​ 中断的实现机制Linux中中断的处理机制是依赖于体系结构的(处理器、中断控制器、体系结构的设计、机器本身)。下图是中断的路由​ 关于中断的下半部我们为什么需要下半部?因为我们要把中断处理中需要做的工作区分开来:中断处理程序中只处理那些有严格时间限制的工作比如复位硬件对中断进行应答等。而那些可以拖到后面做的或者说有可能睡眠的处理都应当放到下半部去处理这样做的目的很显然就是让中断处理程序尽可能的简洁明快在适当的时机下半部会开中断执行​ 中断控制为什么要控制中断?控制中断的原因说到底还是为了要进行同步。通过禁止中断可以确保该中断不会抢占当前运行的代码。禁止中断还可以禁止内核抢占。需要注意的是中断都是对每处理器而言(中断堆栈)也就是说禁止中断并不能够保证自己使用的数据不会被其他处理器的并发进程所访问到。因此如果在使用某些全局的数据时需要考虑对其进行加锁保护。即:锁提供机制防止来自其他处理器(当然也可以是本处理器)的并发访问中断提供机制防止来自其他中断处理程序的并发访问。​ 禁止和激活中断这里需要注意的是内核提供两类接口:禁止激活中断保存恢复中断状态。前者比较傻瓜会无条件的禁止激活中断这需要使用者对当前的中断状态十分确定。而后者则相对更容易使用免去了判断另外关于cli()与sti():在版本之前的内核提供“禁止所有处理器上的中断”这样的功能现在已经去掉了需要开发人员用锁来避免并发。这么做的好处是是的代码更加流线化不会簇拥成团。而且使用粒度更细的锁会比全局锁要效率高。​ 禁止指定中断线我们当然不用禁止全局的中断有时候禁止某一条中断线就可以了这是指:凡是在该中断线上产生的中断都将不会报告给处理器。一般对于有多个中断处理程序共享的中断线并不建议使用这个功能因为这会导致这条线上的其他的设备无法传递中断。​ 中断系统的状态有时候我们需要判断代码所处的状态:是否在中断上下文中。因为有些操作是只有在进程上下文中才能够进行的比如睡眠。系统提供接口来判断中断是否被禁止、是否处于中断上下文、是否正在执行中断处理程序。​ 下半部一般的中断处理都会分为两个部分前面讲到的中断处理程序只是所谓的上半部这是系统处理中断不可或缺的一部分。但是由于中断处理程序本身的局限仅靠上半部是无法高效的处理系统的所有中断的这就需要下半部来提供支持。​ 为什么需要下半部​ 上半部的局限、​ 中断处理程序异步执行且有可能打断其他代码包括其他的中断处理程序、​ 中断处理程序执行时会禁止该中断同级的其他中断甚至禁止全局所有中断、​ 往往需要对硬件进行操作、​ 中断处理程序在中断上下文中运行有很多限制以上几点就要求中断处理程序不仅要简洁、高效而且对于阻塞这种行为也是不能支持的这就导致上半部的限制很多。​ 使用下半部、​ 处理中断时工作推后到下半部的原因就是为了突破上面提到的局限性要尽可能的将那些可以推后执行的工作都放到下半部提高系统的响应速度、​ 下半部何时被调用?这个跟中断处理选择用何种下半部机制有关可以是推后一段时间也可以是通过定时器、​ 下半部的特点:在进行处理的时候随时都有可能响应中断、​ 除了Linux很多其他的操作系统也采用了同样的机制​ 下半部介绍、​ 下半部的实现方式在的内核中有种:软中断、tasklet、工作队列。软中断用的比较少只有有限的几种使用场景更多的是使用tasklet、​ 内核定时器同样也能够将工作推后一段时间(精确的)进行​ 软中断​ 软中断的实现、​ 软中断是在内核编译期间静态分配的不能够动态裁剪。系统定义了一个个元素的数组但是目前只用到了寥寥几个。多数还是通过tasklet来实现、​ 软中断不会抢占相同处理器上的其他软中断软中断会被中断给打断、​ 软中断的执行:中断处理程序在返回之前将对应的软中断进行标记(触发软中断)然后系统会在合适的时机检查该标记并执行软中断(从中断处理程序返回时、在ksoftirqd内核线程中、显示检查与处理软中断的代码)。​ 软中断的使用、​ 软中断是给系统中对时间要求最严格以及最重要的下半部来使用。目前只有两个子系统在使用:网络子系统以及SCSI子系统、​ 执行软中断处理程序的时候能够相应中断但自己不能睡眠、​ 软中断虽然可以禁止本处理器上的同类软中断但是对不同处理器的同类软中断是没有限制的(这就意味着潜在的数据并发访问)。因此我们需要考虑同步(加锁、或者使用每处理器数据)、​ 对于软中断只有执行频率很高连续性要求很高的情况下才考虑使用​ Tasklet​ tasklet的实现、​ tasklet的实现是基于软中断的所以其本身也是软中断、​ tasklet可以静态定义也可以动态创建​ tasklet的调度、​ 已触发的tasklet分为两类:普通优先级高优先级的软中断(前面提到过)、​ Tasklet调度函数首先检查状态若已经被调度过一次则立刻返回、​ 保存中断状态禁止本地中断、​ 设置tasklet需要处理的标记并开中断、​ 在合适的时候执行dosoftirq(),通过内部调用获取对应状态的tasklet链表对每一个tasklet进行处理:如果是RUN状态则跳过否则标记为RUN并执行之执行后取消RUN的状态标记总的来说:每一个tasklet都重复设置HISOFTIRQTASKLETSOFTIRQ这个软中断进行当一个tasklet被调度时某一类软中断被唤醒并被特殊的处理函数进行处理该函数处理执行所有被触发的tasklet(不同类型的tasklet可以同时执行同类的则只能有一个)​ tasklet的使用、​ tasklet的使用比较简单步骤就是创建(静动)、注册自己的处理函数、调度、或者从待运行链表中删除、​ 注意你的处理函数中不应该使用信号量不应该进行睡眠、​ 注意对和其他类型tasklet、软中断等进行了共享的数据进行加锁保护​ 关于ksoftirqd内核线程问题描述:软中断与tasklet(实际上也是软中断)被触发的频率实际上是相当高的而且软中断自己还会重新触发软中断(比如网络子系统)这么一来就很有可能导致用户空间甚至得不到处理器时间长时间处于饥饿状态两个简单的方案:一是只要还有被触发的待处理的软中断本次执行就要负责处理中途触发的软中断也要处理。二是不处理重新触发的软中断等到下一次执行。上述两个方案的不足:前者在系统负载很高的时候软中断会被不停的触发以至于用户空间几乎都得不到响应后者虽然保证了用户进程不会挨饿但是却牺牲了软中断的性能在系统空闲时没有充分利用系统资源ksoftirqdn线程:这组内核线程是上述两种方案的最后折中产物该线程每处理器一个并以最低nice值运行。内核在每次执行软中断时都不会处理重新触发的软中断该工作由ksoftirqd线程进行。当负载较高时其他线程由于优先级较高自然能够获取处理器资源相反当系统较空闲时ksoftirqd线程能被立刻调度那么软中断也就可以被立刻执行。下面是ksoftirqd:​ 工作队列​ 原理与实现、​ 工作队列是内核提供的第三种下半部机制与前两种有所不同最主要的区别就是工作队列将工作推后给一个内核线程eventsn去执行。意味着可以进行睡眠意味着当需要信号量、阻塞、大量内存时工作队列应该是你的首选、​ 每个处理器都会有一个工作者线程也同时对应一个workquestruct用户将需要进行处理的工作挂到工作队列中当线程被调用则会判断工作队列是否为空为空则睡眠否则执行队列中的任务、​ 工作者队列一般只有系统默认的event类型对应到系统中是每个处理器一个events线程。如果要增加工作队列类型那么会导致增加处理器个数个内核线程所以增加类型一定要慎重​ 使用工作队列、​ 可以通过静态方式(DECLAREWORK)或者动态方式(INITWORK)定义自己的工作队列、​ 处理函数虽然运行在进程上下文但不应该访问用户空间的数据、​ 默认情况下处理函数允许响应中断不持有任何锁可以在需要的时候进行睡眠、​ 调度工作队列时可以简单指明需要调度也可以具体指明经过多少时钟节拍后再进行调度。同时内核也提供了刷新工作队列的接口(睡眠等待所有工作完成)有时候会需要这样的刷新操作来确保不再有待处理的工作、​ 如果有需要可以定义新的工作队列类型​ 下半部之间加锁、​ 不同类tasklet之间需要考虑数据的同步、​ 软中断之间需要考虑数据同步、​ 进程上下文与下半部共享数据在访问数据前要禁止下半部处理并获取锁、​ 中断上下文与下半部共享数据在访问数据前要禁止中断并获取锁、​ 工作队列由于可能睡眠也需要考虑数据同步​ 实现自己的中断我们可以在系统中添加属于自己的中断处理包括中断处理程序以及可能需要的下半部。​ 注册中断处理程序在编写中断处理程序之前需要申请中断线并且注册自己的处理函数。这里需要注意的有:中断线是可以多个设备共享的当共享中断线时通过设备id来进行区分初始化硬件和注册中断处理函数的顺序要对避免在硬件初始化之前就开始执行中断处理程序。​ 编写中断处理程序、​ 通常标记为static、​ 至少也要通知硬件中断已经收到、​ 对于较复杂的设备可能需要发送、接受数据甚至做一些扩展工作、​ 扩展工作应当尽量放到下半部、​ 一般会在处理程序中先关中断所以可以不用考虑重入(中断的嵌套只会是不同类型的中断)、​ 如果访问其他共享数据比如和其他高优先级中断处理程序共享的数据时要考虑同步问题、​ 多个设备可以共享中断线当产生中断时内核会依次调用注册在该中断线上的所有处理函数。这时会根据设备id进行区分​ 下半部的选择简单来说这么进行选择:是否需要睡眠?如果需要那么就只有选择工作队列否则就使用tasklet如果需要很好的性能支持那就考虑软中断​ 关于异常异常通常由处理器产生产生时必须考虑与处理器的时钟进行同步。实际上异常也常常被称为同步中断。处理器在执行到错误指令(比如被除)或者发生特殊情况(比如缺页)时必须要靠内核来进行处理处理器就会产生一个异常前面几节对硬件产生的异步中断的讨论大多也适用于异常

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/8

Linux_学习笔记_-_中断

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利