Linux 中断处理浅析
最近在研究异步消息处理, 突然想起linux内核的中断处理, 里面由始至终都贯穿着”重要的事马上做, 不重要的事推后做”的异步处理思想. 于是整理一下~
第一阶段--获取中断号
每个CPU都有响应中断的能力, 每个CPU响应中断时都走相同的流程. 这个流程就是内核提供的中断服务程序.
在进入中断服务程序时, CPU已经自动禁止了本CPU上的中断响应, 因为CPU不能假定中断服务程序是可重入的.
中断处理程序的第一步要做两件事情:
1. 将中断号压入栈中; (不同中断号的中断对应不同的中断服务程序入口)
2. 将当前寄存器信息压入栈中; (以便中断退出时恢复)
显然, 这两步都是不可重入的(如果在保存寄存器值时被中断了, 那么另外的操作很可能就把寄存器给改写了, 现场将无法恢复), 所以前面说到的CPU进入中断服务程序时要自动禁止中断.
栈上的信息被作为函数参数, 调用do_IRQ函数.
第二阶段--中断串行化
进入do_IRQ函数, 第一步进行中断的串行化处理, 将多个CPU同时产生的某一中断进行串行化. 其方法是如果当前中断处于”执行”状态(表明另一个CPU正在处理相同的中断), 则重新设置它的”触发”标记, 然后立即返回. 正在处理同一中断的那个CPU完成一次处理后, 会再次检查”触发”标记, 如果设置, 则再次触发处理过程.
于是, 中断的处理是一个循环过程, 每次循环调用handle_IRQ_event来处理中断.
第三阶段--关中断条件下的中断处理
进入handle_IRQ_event函数, 调用对应的内核或内核模块通过request_irq函数注册的中断处理函数.
注册的中断处理函数有个中断开关属性, 一般情况下, 中断处理函数总是在关中断的情况下进行的. 而调用request_irq注册中断处理函数时也可以设置该中断处理函数在开中断的情况下进行, 这种情况比较少见, 因为这要求中断处理代码必须是可重入的. (另外, 这里如果开中断, 正在处理的这个中断一般也是会被阻塞的. 因为正在处理某个中断的时候, 硬件中断控制器上的这个中断并未被ack, 硬件不会发起下一次相同的中断.)
中断处理函数的过程可能会很长, 如果整个过程都在关中断的情况下进行, 那么后续的中断将被阻塞很长的时间.
于是, 有了soft_irq. 把不可重入的一部分在中断处理程序中(关中断)去完成, 然后调用raise_softirq设置一个软中断, 中断处理程序结束. 后面的工作将放在soft_irq里面去做.
第四阶段--开中断条件下的软中断
上一阶段循环调用完当前所有被触发的中断处理函数后, do_softirq函数被调用, 开始处理软件中断.
在软中断机制中, 为每个CPU维护了一个若干位的掩码集, 每位掩码代表一个中断号. 在上一阶段的中断处理函数中, 调用raise_softirq设置了对应的软中断, 到了这里, 软中断对应的处理函数就会被调用(处理函数由open_softirq函数来注册).
可以看出, 软中断与中断的模型很类似, 每个CPU有一组中断号, 中断有其对应的优先级, 每个CPU处理属于自己的中断. 最大的不同是开中断与关中断.
于是, 一个中断处理过程被分成了两部分, 第一部分在中断处理函数里面关中断的进行, 第二部分在软中断处理函数里面开中断的进行.
由于这一步是在开中断条件下进行的,这里还可能发生新的中断(中断嵌套),然后新中断对应的中断处理又将开始一个新的第一阶段~第三阶段。在新的这个第三阶段中,可能又会触发新的软中断。但是这个新的中断处理过程并不会进入第四阶段,而是当它发现自己是嵌套的中断时,完成第三阶段之后就会退出了。也就是说,只有第一层中断处理过程会进入第四阶段,嵌套发生的中断处理过程只执行到第三阶段。
然而嵌套发生的中断处理过程也可能会触发软中断,所以第一层中断处理过程在第四阶段需要是一个循环的过程,需要循环处理嵌套发生的所有软中断。为什么要这样做呢?因为这样可以按软中断触发的顺序来执行这些软中断,否则后来的软中断可能就会先执行完成了。
极端情况下,嵌套发生的软中断可能非常多,全部处理完可能需要很长的时间,于是内核会在处理完一定数量的软中断后,将剩下未处理的软中断推给一个叫ksoftirqd的内核线程来处理,然后结束本次中断处理过程。
第五阶段--开中断条件下的tasklet
实际上, 软中断很少直接被使用. 而第二部分开中断情况下的进行的处理过程一般是由tasklet机制来完成的.
tasklet是由软中断引出的, 内核定义了两个软中断掩码HI_SOFTIRQ和TASKLET_SOFTIRQ(两者优先级不同), 这两个掩码对应的软中断处理函数作为入口, 进入tasklet处理过程.
于是, 在第三阶段的中断处理函数中, 完成关中断的部分后, 然后调用tasklet_schedule/tasklet_hi_schedule标记一个tasklet, 然后中断处理程序结束. 后面的工作由HI_SOFTIRQ/TASKLET_SOFTIRQ对应的软中断处理程序去处理被标记的tasklet(每个tasklet在其初始化时都设置了处理函数).
看上去, tasklet只不过是在softirq的基础上多了一层调用, 其作用是什么呢? 前面说过, softirq是与CPU相对应的, 每个CPU处理自己的softirq. 这些softirq的处理函数需要设计为可重入的, 因为它们可能在多个CPU上同时运行. 而tasklet则是在多个CPU间被串行化执行的, 其处理函数不必考虑可重入的事情.
然而, softirq毕竟还是要比tasklet少绕点弯路, 所以少数实时性要求相对较高的处理过程还是在精心设计之后, 直接使用softirq了. 比如: 时钟中断处理过程, 网络发送/接收处理过程.
结尾阶段
CPU接收到中断以后, 以历以上五个阶段, 中断处理完成. 最后需要恢复第一阶段中被保存在栈上的寄存器信息. 中断处理结束.
关于调度
上面的流程中, 还隐含了一个问题, 整个处理过程是持续占有CPU的(除了开中断情况下可能被新的中断打断以外). 并且, 中断处理的这几个阶段中, 程序不能够让出CPU!
这是由内核的设计决定的, 中断服务程序没有自己的task结构(即操作系统教科书上说的进程控制块), 所以它不能被内核调度. 通常说一个进程让出CPU, 在之后如果满足某种条件, 内核会通过它的task结构找到它, 并调度其运行.
这里可能存在两方面的问题:
1. 连续的低优先的中断可能持续占有CPU, 而高优先的某些进程则无法获得CPU;
2. 中断处理的这几个阶段中不能调用可能导致睡眠的函数(包括分配内存);
对于第一个问题, 较新的linux内核增加了ksoftirqd内核线程, 如果持续处理的softirq超过一定数量, 则结束中断处理过程, 然后唤醒ksoftirqd, 让它来继续处理. 虽然softirq可能被推后到ksoftirqd内核线程去处理, 但是还是不能在softirq处理过程中睡眠, 因为不能保证softirq一定在ksoftirqd内核线程中被处理.
据说在montavista(一种嵌入式实时linux)中, 将内核的中断机制做了修改. (某些中断的)中断处理过程被赋予了task结构, 能够被内核调度. 解决了上述两个问题. (montavista的目标是实时性, 这样的做法牺牲了一定的整体性能.)
工作队列
linux基线版本的内核在解决上述问题上, 提供了workqueue机制.
定义一个work结构(包含了处理函数), 然后在上述的中断处理的几个阶段的某一步中调用schedule_work函数, work便被添加到workqueue中, 等待处理.
工作队列有着自己的处理线程, 这些work被推迟到这些线程中去处理. 处理过程只可能发生在这些工作线程中, 所以这里可以睡眠.
内核默认启动了一个工作队列, 对应一组工作线程events/n(n代表处理器编号, 这样的线程有n个). 驱动程序可以直接向这个工作队列添加任务. 某些驱动程序还可能会创建并使用属于自己的工作队列.
Linux 中断处理浅析的更多相关文章
- SQL Server on Linux 理由浅析
SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...
- linux中断处理原理分析
Tasklet作为一种新机制,显然可以承担更多的优点.正好这时候SMP越来越火了,因此又在tasklet中加入了SMP机制,保证同种中断只能在一个cpu上执行.在软中断时代,显然没有这种考虑.因此同一 ...
- Linux中断处理体系结构分析
Linux中断处理体系结构分析(一) 异常,就是可以打断CPU正常运行流程的一些事情,比如外部中断.未定义指令.试图修改只读的数据.执行swi指令(Software Interrupt Instruc ...
- [国嵌攻略][119][Linux中断处理程序设计]
裸机中断: 1.中断统一入口. 2.注册中断处理程序. 3.根据中断源编号,调用中断处理程序. Linux中断 1.在entry-armv.S中的_irq_svc是中断统一入口. 2.获取产生中断源的 ...
- linux网桥浅析
linux网桥浅析 原文链接:http://hi.baidu.com/_kouu/item/25787d38efec56637c034bd0 什么是桥接?简单来说,桥接就是把一台机器上的若干个网络接口 ...
- linux中断处理上下部分
一.linux中断处理为什么要分为上下部 1.1. 中断处理的上半部(top half,又叫顶半部)和处理的下半部(bottom half,又叫底半部) 1.1. linux中断处理不参与调度,故中断 ...
- Linux.中断处理.入口x86平台entry_32.S
Linux.中断处理.入口x86平台entry_32.S Linux.中断处理.入口x86平台entry_32.S 在保护模式下处理器是通过中断号和IDTR找到中断处理程序的入口地址的.IDTR存的是 ...
- 【转】Linux中断处理学习笔记
原文网址:http://www.cnblogs.com/GT_Andy/archive/2011/06/21/2086100.html 1.Linux中断的注册与释放: 在<linux/inte ...
- Linux中断处理(二)
与Linux设备驱动中中断处理相关的首先是申请与释放IRQ的API request_irq()和free_irq(),request_irq()的原型为:int request_irq(unsigne ...
随机推荐
- 运行impala tpch
1.安装git和下载tpc-h-impala脚步 [root@ip-172-31-34-31 ~]# yum install git [root@ip-172-31-34-31 ~]# git clo ...
- SQL数据库,使用事务执行增删改操作,给自己一个后悔的机会
内容并不复杂,使用起来也比较简单. 主要使用以下3条SQL语句: 开始事物:BEGIN TRAN(全拼 TRANSACTION 亦可)提交事物:COMMIT TRAN回滚事务:ROLLBACK TRA ...
- Theoretical comparison between the Gini Index and Information Gain criteria
Knowledge Discovery in Databases (KDD) is an active and important research area with the promise for ...
- asp.net MVC code first Migrations : Model 同步到DB中
找来找去,看来用这个功能的人很少. http://www.it165.net/pro/html/201403/10653.html 步骤: 1,在程序包管理控制台上,Enable-Migrations ...
- php web系统多域名登录失败解决方法
下面只是简单的逻辑结构,对于正式的系统需要做具体的处理. 这里需要注意的是:加解密一定需要做安全验证.但是这个方法也不够完美,两个站点必须有相同一级域名:另外这种完全基于cookie的方式,安全性不够 ...
- 遗传算法的C语言实现(二)-----以求解TSP问题为例
上一次我们使用遗传算法求解了一个较为复杂的多元非线性函数的极值问题,也基本了解了遗传算法的实现基本步骤.这一次,我再以经典的TSP问题为例,更加深入地说明遗传算法中选择.交叉.变异等核心步骤的实现.而 ...
- 安装mysql sever 向导失败,最后一步无响应
在配置apache+php+mysql环境的时候,apache和php都可以运行,这里提供两个安装教程(window环境) http://apps.hi.baidu.com/share/detail/ ...
- Ubuntu 14.10下搭建简易FTP服务器[vsftpd]
Ubuntu下公认最易上手的ftp软件是vsftpd,既然标题都说了是“简易”的,那么必然是用最大众的..下面是正题 目标需求:搭建一个允许匿名/本地登录的FTP,并且支持上传/下载/修改功能,同时F ...
- ios--进程/多线程/同步任务/异步任务/串行队列/并行队列(对比分析)
现在先说两个基本的概念,啥是进程,啥是线程,啥又是多线程;先把这两个总是给弄清再讲下面的 进程:正在进行的程序,我们就叫它进程. 线程:线程就是进程中的一个独立的执行路径.这句话怎么理解呢! 一个程序 ...
- IT之梦
生活原本不孤单,可惜人们总爱感叹 日子其实很简单,而我却不甘平淡 工作中我尽情的挥洒热汗,只为让成功离自己更近一点 生活中我为人和善,只为人生的路上多一个伙伴 时间不等人,IT尚遥远 我愿舍身敬业,誓 ...