最近在研究异步消息处理, 突然想起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

Linux 中断处理浅析相关推荐

  1. linux进程调度浅析

    linux进程调度浅析 操作系统要实现多进程,进程调度必不可少. 有人说,进程调度是操作系统中最为重要的一个部分.我觉得这种说法说得太绝对了一点,就像很多人动辄就说"某某函数比某某函数效率高 ...

  2. 【Linux系统编程】Linux 进程调度浅析

    概述 操作系统要实现多进程,进程调度必不可少.有人说,进程调度是操作系统中最为重要的一个部分.我觉得这种说法说得太绝对了一点,就像很多人动辄就说"某某函数比某某函数效率高XX倍"一 ...

  3. ARM GIC简介与Linux中断处理分析

    先简单说明一下GIC(具体详尽的介绍请查阅ARM GIC相关文档) GIC即general interrupt controller. 它是一个架构,版本历经了GICv1(已弃用),GICv2,GIC ...

  4. 【Linux系统编程】Linux线程浅析

    00. 目录 文章目录 00. 目录 01. 进程和线程区别 02. LinuxThreads 03. NPTL 04. NGPT 05. 附录 01. 进程和线程区别 在许多经典的操作系统教科书中, ...

  5. 【Linux系统编程】Linux 线程浅析

    进程和线程的区别与联系 在许多经典的操作系统教科书中,总是把进程定义为程序的执行实例,它并不执行什么, 只是维护应用程序所需的各种资源,而线程则是真正的执行实体. 为了让进程完成一定的工作,进程必须至 ...

  6. linux中断处理汇编入口,Linux中断处理体系结构分析(一)

    中断也是一种异常,之所以把它单独的列出来,是因为中断的处理与具体的开发板密切相关,除一些必须.共用的中断(比如系统时钟中断.片内外设UART中断)外,必须由驱动开发者提供处理函数.内核提炼出中断处理的 ...

  7. Linux中断处理:上半部和下半部

    <Linux中断处理:上半部和下半部> <Linux网络协议栈:中断下半部处理> 目录 中断处理 - 上半部(硬中断) 中断处理相关结构 注册中断处理入口 处理中断请求 中断处 ...

  8. docker CE on Linux示例浅析(四)swam群集配置

    概述 github项目地址:https://github.com/superwujc 尊重原创,欢迎转载,注明出处:https://my.oschina.net/superwjc/blog/30534 ...

  9. [转载] Linux网桥浅析

    linux网桥浅析 原文链接:http://hi.baidu.com/_kouu/item/25787d38efec56637c034bd0 什么是桥接? 简单来说,桥接就是把一台机器上的若干个网络接 ...

最新文章

  1. 宽依赖和窄依赖_Spark术语解释及宽窄依赖执行原理,代码分析
  2. html语言设计表格,HTML标记语言——表格标记
  3. 【强化学习】DQN及其延伸算法
  4. .net core 5 IIS Api网站部署需要注意
  5. 2008年10月试题电子商务与电子政务全国
  6. 将哔哩哔哩手机端缓存视频导出为正常mp4视频.
  7. 推荐3款手机远程控制电脑的软件 专业 好用 免费
  8. 一小时搞定简单VBA编程 Excel宏编程快速上手
  9. 80端口有什么用,80端口被禁用怎么解决
  10. win7下关闭wps热点和wps云文档自动漫游的方法
  11. Matlab建的模型如何导入MS中,lammps输出的模型如何导入MS中建模
  12. root 红米note5_怎么开启红米Note 5的ROOT权限
  13. 用python实现字符串数据的标签数字化
  14. 并发编程系列之Semaphore
  15. Mysql的锁以及MVCC解决事务隔离级别
  16. 蓝奏云第三方cmd客户端(LanZouCloud-CMD)Cookie内容设置方法
  17. 将csv写入mysql数据库_从.csv文件到数据库
  18. NumPy简明教程(二、数组1)
  19. 抢东西用的时间软件_紧急重要四象限软件用哪款?这款时间管理便签软件适合你...
  20. 中标麒麟V7.0-x64版本安装QT

热门文章

  1. 利用云功能和API监视Google表格中的Cloud Dataprep作业状态
  2. PHP操作MySQL数据库(连接、增删改操作)
  3. 女性自我的迷宫:看EMI的人体自拍
  4. 恐怖与暴力美学 + 妖魔化:《人皮客栈》观看笔记
  5. ISERDES Guidelines
  6. mac地址修改_如何修改手机MAC地址?
  7. linux打印jvm内存堆栈_5款强大的JVM 性能调优监控工具
  8. python全文检索引擎_Python中使用haystack实现django全文检索搜索引擎功能
  9. python删除指定天数前的文件_python 删除指定时间间隔之前的文件实例
  10. 全志线刷工具如何刷linux,全志 Allwinner V3S 开发环境搭建 (二)安装必要工具