文档章节

Linux 中断处理浅析

oschina_00
 oschina_00
发布于 2016/12/29 17:39
字数 2522
阅读 4
收藏 0

最近在研究异步消息处理, 突然想起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个). 驱动程序可以直接向这个工作队列添加任务. 某些驱动程序还可能会创建并使用属于自己的工作队列.

来源:ctthunagchneg   

链接:http://blog.csdn.net/ctthuangcheng/article/details/8915057

本文转载自:链接:http://blog.csdn.net/ctthuangcheng/article/details/8915057

oschina_00
粉丝 5
博文 101
码字总数 0
作品 0
廊坊
私信 提问
中断处理浅析

摘要:本章将向读者依次解释中断概念,解析Linux中的中断实现机理以及Linux下中断如何被使用。作为实例我们第一将向《i386体系结构》一章中打造的系统加入一个时钟中断;第二将为大家注解RTC...

长平狐
2012/09/03
907
0
Linux进程状态(ps stat)之R、S、D、T、Z、X

Linux是一个多用户,多任务的系统,可以同时运行多个用户的多个程序,就必然会产生很多的进程,而每个进程会有不同的状态。 R Linux进程状态:R (TASK_RUNNING),可执行状态。 只有在该状态的...

mskk
02/14
19
0
Linux RPS/RFS 实现原理浅析

本文快速解析一下RPS/RFS的基本原理。 RPS-Receive Packet Steering 下面这个就是RPS的原理: 其实就是一个软件对CPU负载重分发的机制。其使能的作用点在CPU开始处理软中断的开始,即下面的地...

dog250
2018/04/21
0
0
从Unix分层内核栈以及中断处理看Linux内核的另类

如果你一开始就读linux内核,那么你的思路会变得非常开阔,如果你读过unix内核,那么你会惊叹于linux内核的巧妙,如果你连NT的内核也了解,那么你会发现linux内核真是个另类,本文从内核栈的...

晨曦之光
2012/04/10
216
0
深入浅出 Linux设备驱动中断处理介绍

与Linux设备驱动中中断处理相关的首先是申请与释放IRQ的API: request_irq()和free_irq()。 request_irq()的原型为: irq是要申请的硬件中断号; handler是向系统登记的中断处理函数,是一个...

JavaGG
2009/05/07
557
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
35分钟前
36
0
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
今天
9
0
计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
昨天
6
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
昨天
7
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部