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,一经查实,立即删除!

相关文章

C#中泛型的相关知识点总结

一、概念 1.1 泛型 泛型是什么? 书本告诉我们泛型是通过通过参数化类型的方法在同一份代码上对多种数据类型进行调用。也即是说,如果同一个代码需要使用不同的数据类型的话就可以定义一个泛型的类或者方法。 泛型的优点是什么? 1.通过使用…

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

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

判断字符串中是否为数字的三种方法

//1用JAVA自带的函数 public static boolean isNumeric(String str){for (int i str.length();--i>0;){ if (!Character.isDigit(str.charAt(i))){return false;}}return true;}//2用正则表达式 public static boolean isNumeric(String str){ Pattern pattern Pattern.…

【图像处理】——Python+opencv实现图像的hu不变矩特征提取(含原理、推导过程、应用、代码等)

目录 转载本文请注明详细地址本文介绍了矩和图像矩的含义本文介绍了不变矩的计算、应用本文介绍了如何计算图像相似度一、思维导图 二、普通矩的定义 1、零阶矩 2、二阶矩

MSSQL-to-MySQL v5.3, 从MSSQL迁移到mySQL的最佳工具

将现有的MSSQL数据库迁移到MySQL数据库,尝试了很多种工具 MySQL Workbench / MSSQL to MySQL Export / DB Converter / openDBcopy 都有这样那样的问题。 最后发现就MSSQL-to-MySQL好一点,能够保证所有表和数据成功迁移,并且字段类型都比较正确。 只是对…

C#窗体应用程序崩溃解决方法总结

一、内存不足 内存是最常见的导致程序崩毁的原因,常用解决方式有如下几种。 算法中声明的占内存较大的全局变量或类中声明的私有变量在循环或运行结束后需进行释放,手动设置Dispose(),然后GC.Collect()。对一些重复调用的类避免多次实例化。…

【学习的心得】——“快餐”的效率与“挖掘”的重要性

从事Python图像处理和机器学习方向已经有大半年了,现在作为还是一个研究生的我,大部分时间都是在完成老师给的课题任务,但是这几个月下来我感觉和老师的意见有点分歧了甚至跟一些同学都有所意见分歧了。 Python虽然是最近几年火起来的语言&a…

Unity3D Input按键系统

默认输入轴: Horizontal 和 Vertical被映射到w, a, s, d键和方向键 Fire1, Fire2, Fire3被分别映射到Ctrl,Option(Alt)和Command键 Mouse X 和 Mouse Y被映射到鼠标移动增量 Window Shake X 和 Window Shake Y 被映射到窗口的移动…

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…

【图像处理】——纹理特征提取方法(LBP局部二值模式和GLCM灰度共生矩阵)

纹理特征提取方法 局部二值模式(LBP) (结构法) Local binary patterns 原理 将像素点的邻域八个像素点与中心像素点值进行比较,大于设为1,小于设为0,这样就会得到一个邻域值为1和0的格子,将这八个值按照一定的规则排列成一个二进制的数字,并且转换为十进制作为中心像…

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状态管…

jquery检测浏览器类型

使用jquery如下代码检测浏览器版本时:出问题,在检测IE浏览器,如果版本是IE11时,会出现 $.browser.msie的返回值是false,$.browser.mozilla的返回值是true,即把IE11检测成火狐了 结局办法 判断IE浏览器用 …

【leetcode❤python】 9. Palindrome Number

#回文数#Method1:将整数转置和原数比较,一样就是回文数;负数不是回文数#这里反转整数时不需要考虑溢出,但不代表如果是C/C等语言也不需要考虑class Solution(object): def isPalindrome(self, x): """ …

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

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

“RuntimeWarning: overflow encountered in ubyte_scalars像素加减运算溢出异常”原因以及解决办法

转载本文请注明详细地址本文介绍了像素点相加减溢出的原因与解决方法 目录 原因: 解决方法: 原因: 这个问题一般是会出现在图像处理像素的加减中,出现的原因是因为图片的像素一般是八位即最大值是256,最小值是0&…

二叉树重建

一、已知先序遍历和中序遍历。求后序遍历。http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId944 依据先序遍历和中序遍历还原二叉树的主要思想: 1、先序遍历序列的第一个元素必然是根节点,能够由此获取二叉树的根节点。 2、依据根节点&…

asyn4j -- java 异步方法调用框架

asyn4j 是一个java异步方法调用框架,基于消费者与生产者模式。包括了异步方法执行,异步回调执行,异步工作缓存模块.支持Spring. 让我们写异步方法不再写很多的相关多线程代码。用asyn4j轻松搞定异步方法调用.提高程序的响应能力.转载于:https…

Pytorch基础(二)—— Transforms详解

一、概念 Transforms是pytorch的图像处理工具包,是torchvision模块下的一个一个类的集合,可以对图像或数据进行格式变换,裁剪,缩放,旋转等,在进行深度学习项目时用途很广泛。下面对Transforms内的常见类的…