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个). 驱动程序可以直接向这个工作队列添加任务. 某些驱动程序还可能会创建并使用属于自己的工作队列.

转载于:https://www.cnblogs.com/probemark/p/5947236.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/256236.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用scikit-learn研究局部线性嵌入(LLE)

1. scikit-learn流形学习库概述 在scikit-learn中,流形学习库在sklearn.manifold包中。里面实现的流形学习算法有: 1)多维尺度变换MDS算法:这个对应的类是MDS。MDS算法希望在降维时在高维里样本之间的欧式距离关系在低维可以得到保…

iOS app 企业内部发布及HTTPS服务器配置

转自: http://www.cnblogs.com/cocoajin/p/4082488.html iOS企业内部发布及HTTPS服务器配置 一:所需的条件 1. 苹果开发者证书,企业版 299$ 版本 2. ssl 证书,即https使用的服务器证书 3. web服务器,支持https 4. 一个域名&#x…

Pytorch超简单安装教程

安装Pytorch 1.1 安装Annaconda 安装Pytorch首先需要安装Annaconda,按照教程,安装了Annaconda5.2.0的版本。 路径 记住安装路径即可,其余均选默认。 1.2 安装Pytorch 第一步,打开Anaconda Prompt 。然后输入 conda create -n…

44. 源代码解读-RocketMQ-架构

1. 前言 1.1 github源代码 https://github.com/apache/rocketmq 1.2 github其他客户端,比如c,php https://github.com/apache/rocketmq-externals 1.3 运行进程 RocketMQ分成两个进程运行 NamesrvBrokerNamesrv,命名服务,主要负责Broker状态管…

Pytorch基础(一) —— tensorboard的应用

一、简介与安装方法 1.1 概念 Tensorboard 是 TensorFlow 的一个工具包,用于展示网络图、张量的指标变化和分布情况,如权重W、偏置B、卷积层数、全连接层数等参数,使用该工具可以方便观察神经网络训练过程,分析学习模型训练的效…

【WIN10】WIN2D——基本圖形的繪製

DEMO下載地址:http://yunpan.cn/c3iNuHFFAcr8h (提取码:8e48) 先看一個截圖: 繪製了一些基本形狀。 DEMO的繪製代碼都非常簡單,不想在博客裡細說了,看代碼更為清晰些。 可能繪製扇形的代碼有些麻…

python socket 网络编程

socket 套接字:网络接口。 我们在网络上需要传输自己需要的数据,我们在网络上传输数据使用的是网络协议, 而套接字就是我们将数据从本地采用协议传输的接口 socket模型: socket族: #AF_UNIX 被使用在类unix系统之间进行…

Python中利用plt显示中文标题解决方案

解决方法 plt.rcParams[font.sans-serif][SimHei] plt.rcParams[axes.unicode_minus] False plt.title(灰度级别频率图) plt.show()

Pytorch基础(四)—— 卷积层

一、概念 卷积从数学的角度讲是一种矩阵的运算方法。我们可以用一个卷积核对一个矩阵进行卷积运算,具体运算过程图示可以见pytorch官网。 卷积运算按输入数据的通道数可分为单通道和多通道两种。 单通道是指卷积核只有一个的情况。 多通道包括两种。 分别是单个…

【图像处理】——创建一个新的图片

方法一:直接复制一个已经存在的图片 img.copy() 如果是想生成一个指定大小的图片,则可以通过numpy数组进行创建 方法二:通过numpy创建(注意有坑) img = numpy.zeros((h,w))#h,w是指定的图像的高和宽,这样看似可以其实不然上述方法得到的图像不是8位的,但是图像数组的…

How to make a Logical Volume ON AIX5.3

本文转自 xkdcc 51CTO博客,原文链接:http://blog.51cto.com/brantc/116431,如需转载请自行联系原作者1. 确定要建立的卷大小,比如700M 2. 检查要建立逻辑卷的卷组上的PP大小(PP:物理分区,PP si…

Pytorch基础(五)—— 池化层

一、概念 池化就是把数据压缩的过程,属于下采样的一种方法,可以显著降低神经网络计算复杂度,减少训练中的过拟合,同时可以使数据具有一定的不变性。 池化从方法上来讲可以分为average Pooling、max Pooling、Overlapping Poolin…

Pytorch基础(六)——激活函数

一、概念 激活函数顾名思义,就是一种可以给神经网络注入灵魂的一种方法,也可以称之为激活层。其计算就是将线性的函数转变为非线性函数的过程,只有这样,我们制作的深层神经网络才能无限逼近真实值。 自神经网络发展到目前为止&am…

【NOIP 模拟题】[T1] 等差数列(dp)

【题解】【dp】 【f[i][j]表示以i为结尾&#xff0c;j为公差的子序列个数】 【要注意有负数&#xff0c;所以将公差1000】 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const p9901; int f[1010][2010],n,a[1010]; lo…

走在网页游戏开发的路上(十)

页游资源管理 现在页游的规模越来越来大&#xff0c;游戏内容丰富&#xff0c;资源管理变得很重要。现在一款SNS页游的所有资源可达50M&#xff0c;MMO页游更高达几百M&#xff0c;不可能把资源放到一个文件里面、也不可能一次性加载完所有资源。按200kb/s的下载速度来算&#…

Pytorch基础(七)——线性层(全连接层)

一、概念 在神经网络中&#xff0c;我们通常用线性层来完成两层神经元间的线性变换。 按照官网的解释&#xff0c;Linear.weight也即A&#xff0c; 我们可以称之为权重矩阵&#xff0c;对其转置后乘以输入数据(一般都是一维张量)&#xff0c;加上Linear.bias即b偏置。 二、P…

PureMVC(AS3)剖析:吐槽

PureMVC&#xff08;AS3&#xff09;剖析&#xff1a;吐槽 写在前面 世上没有银弹——不存在适用于所有情况的框架&#xff0c;只有适合的框架。再者任何一个好的东西&#xff08;语言、框架等&#xff09;最终还取决于用的人&#xff0c;语言和框架本身并不能保证用户的代码清…

Pytorch基础(八)——正则化

一、概念 正则化在深度学习领域是为了防止训练结果过拟合而采取的一种方法。 1.1 过拟合 过拟合表示模型的泛化能力较差&#xff0c;体现在实际训练模型上就是在训练集表现很好&#xff0c;但是在测试集的效果一般。 过拟合的原因&#xff1a;1&#xff0c;模型过于复杂。2&…