linux设备驱动:中断处理中的hardirq与softirq详细流程

article/2025/11/7 7:07:42

中断处理的整体框架:
图1
内核用于标识中断上下文(in_interrupt())的变量preempt_count的布局:
图2

  • 按照x86处理器在外部中断发生时的硬件逻辑,在do_IRQ被调用时,处理器已经屏蔽了对外部中断的响应。在图中我们看 到中断的处理大体上被分成两部分HARDIRQ和SOFTIRQ,对应到代码层面,do_IRQ()中调用irq_enter函数可以看做hardirq 部分的开始,而irq_exit函数的调用则标志着softirq部分的开始:
unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{...irq_enter();//handle external interrupt (ISR)...irq_exit();return 1;
}
  • irq_enter()函数的核心调用是__irq_enter(),后者的主要作用是在图2的 preempt_count变量的HARDIRQ部分+1,即标识一个hardirq的上下文,所以可以认为do_IRQ()调用irq_enter函数 意味着中断处理进入hardirq阶段。此时处理器响应外部中断的能力依然是被disable掉的(EFLAG.IF=0),因为ISR基本上属于设备驱动程序涉足的领域,内核无法保证在设备驱动程序的ISR中会否将EFLAG.IF置1(此处涉及可能的中断嵌套以及中断栈溢出问题,可以参考ARM中断处 理的那个帖子),所以我们会在内核代码中看到内核开发者为了尽可能避免非受控的ISR部分给系统带来的损害所做的努力。按照现在内核的设计理念,在 hardirq部分最好不要打开中断,所以处在hardirq上下文中的设备驱动程序的ISR应该尽可能快地返回(所谓只完成最关键的任务),而将耗时的 中断处理善后工作留到softirq部分,因为在softirq部分,内核会使EFLAG.IF=1,所以也意味着softirq部分可以随时被外部中断 所打断。

  • 下面我们重点讨论一下softirq部分的实现原理,do_IRQ()中调用irq_exit函数标志softirq部分 的开始。 irq_exit()函数会首先在图2的preempt_count变量的HARDIRQ部分-1,目的是清除hardirq的上下文标记。然后它有个关键的调用invoke_softirq,用于实际的softirq处理工作:
void irq_exit(void)
{...sub_preempt_count(IRQ_EXIT_OFFSET);if (!in_interrupt() && local_softirq_pending())invoke_softirq();rcu_irq_exit();...
}
  • 其中对in_interrupt()函数的叙述很明确:"…其主要用意是根据当前preempt_count变 量,来判断当前代码是否在一个中断上下文中执行。根据in_interrupt的定义来看,Linux内核认为HARDIRQ、SOFTIRQ以及NMI 都属于interrupt范畴…",所以softirq部分是否被执行,取决于:

    • 1.当前是否在中断上下文, 2. 是否有pending的softirq需要处理。
  • 第一个条件,主要用来防止softirq部分的重入,因为一旦有pending的softirq需要处理,那么invoke_softirq()的调用 (实际的工作发生在__do_softirq函数中)首先会将图2中SOFTIRQ部分+1,这样若在当前正在处理softirq过程中发生了外部中 断,hardirq部分标识了一个pending softirq,那么在irq_exit函数中将直接返回,而不会调用到invoke_softirq。

  • softirq部分的核心代码段如下:

asmlinkage void __do_softirq(void)
{...//获得__softirq_pending变量上保存的pending softirq数据pending = local_softirq_pending();//将图2中SOFTIRQ部分+1,标识softirq上下文,此时in_interrupt()返回true.__local_bh_disable((unsigned long)__builtin_return_address(0), SOFTIRQ_OFFSET);...
restart:/* Reset the pending bitmask before enabling irqs */set_softirq_pending(0);//注意此处,内核调用local_irq_enable打开处理器响应外部中断能力,EFLAG.IF=1,所以接下来的softirq处理时外部中断可以进入处理器local_irq_enable();h = softirq_vec;do {if (pending & 1) {...//调用每个类型的softirq所对应的处理函数,见下图3h->action(h);...}h++;pending >>= 1;} while (pending);//softirq处理结束前,重新关闭中断。中断的再次打开发生在中断的返回,也就是在图1中处理器在执行iret指令时的硬件逻辑,POP EFLAG, EFLAG.IF=1local_irq_disable();//再次检测是否有新的pending softirq,因为softirq执行时可能有新的外部中断进来,如果有,此处一并处理。pending = local_softirq_pending();if (pending && --max_restart)goto restart;...//将图2中SOFTIRQ部分-1,标识softirq上下文的结束__local_bh_enable(SOFTIRQ_OFFSET);
}
  • 对每个类型的softirq的处理发生在上面的do…while…循环中,原理其实非常简单,为节省文字,用下面一个草图来做说明(图3):
    图3
  • 所以do…while…循环实际上是从bit 0遍历__softirq_pending变量,目前该变量的0~9分别对应10个不同类型的softirq,每个softirq对应不同的处理函数,比如HI_SOFTIRQ对应的action为tasklet_hi_action,它与TASKLET_SOFTIRQ的action的原理完全一样,也就是我们平常所说的tasklet。__softirq_pending是个per-CPU型的变量,因为SMP系统中每个处理器都可以独立处理各自到来 的外部中断,也都对应有各自的hardirq栈和softirq栈。

参考链接:详解Linux中断处理中的hardirq与softirq机制
参考书籍:深入Linux设备驱动程序内核机制


http://chatgpt.dhexx.cn/article/3KMLTlLW.shtml

相关文章

Java 字段封装快捷键

快捷键:shift alt s 选择:

Java封装阿里云对象存储OSS

Java封装阿里云对象存储OSS 阿里云对象存储OSS官网 本篇博客简单封装了阿里云的OSS存储中的建立连接;本地文件,输入流和URL三种方式上传文件,获取文件的输入流,删除文件,获取所有文件列表等功能。 OSS官方Api OSSp…

java 枚举 封装操作方法

前言: 由于刚转java项目,所以对于java语言比较陌生,尤其是lambda和一些诸如(一个java文件只能有一个public class)等等的零散知识点之类。。。 使我觉得就语言的层级来说。.net真的超越java不是一星半点。奈何.net跨…

Java封装和封装的案例

Java封装和封装的案例 目录 一、Java封装知识点简介 二、Java程序中的包 三、static关键字、代码块 四、封装的综合应用案例: 一、Java封装知识点简介 1、面向对象三大特性之封装的概念: 隐藏类的某些内部细节,不允许外部程序直接访问…

Java的封装方法

在面向对象程式设计方法中,封装(英文名称:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的…

Java封装如何封装 封装的好处是什么?

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、封装的作用是什么?二、封装的好处三、封装的步骤 1.引入库2.private的应用总结 前言 我要看电视,只需要按一下开关和换台就可以了。…

15、JAVA入门——封装

目录 一、封装 1、封装概述 2、封装的步骤 二、Java里的包 1、包的概述 2、包的定义 3、包的使用 4、注意事项 三、Java访问修饰符 1、类和类成员的访问控制 2、类的访问修饰符 3、类成员的访问修饰符 四、static关键字 1、static特点 2、static修饰属性 3、static修饰方法 4、…

初学java封装

封装 初识java封装 封装的用处: 1.提高程序的安全性,保护数据 2.隐藏代码的实现细节 3.统一接口 4.增加系统可维护性 这里创建一个类 public class Package {//属性私有private String name;//名字private int age; //年龄private int sex;//性别//1.…

java如何实现封装_java如何实现封装

Java中类的封装是如何实现的封装是将对象的信息隐藏在对象内部,禁止外部程序直接访问对象内部的属性和方法。 java封装类通过三个步骤实现: (1)修改属性的可见性,限制访问。 (2)设置属性的读取方法。 (3)在读取属性的方法中,添加对属性读取的限制。 Java中什么叫封装呢? 继…

java封装dll文件_java类封装成dll

1,建立测试类,注意英文注释部分,用汉语直接编译会乱码 public classHello {//native method is used for call other language procedure//if use chinese here then Compile would be gibberish public native voidprintHello();static{ Sys…

java之封装

1.封装 1. 封装 1.1 private关键字 private是一个修饰符,可以用来修饰成员(成员变量,成员方法) 被private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,如果需要被其他类使用&…

【JavaScript】js中非常常见的面试题

文章目录 1、手动实现防抖和节流2、let、const、var 的区别3、箭头函数与普通函数区别4、Promise5、数据类型6、检测数据类型的常用方法1 .typeof2 . instanceof3 .constructor4 . 使用 Object.prototype.toString.call()检测对象类型⭐5 . 自己封装函数6、isArray 7、数组的常…

JS的100道经典面试题(一)只看这四篇就够了,收藏起来以后偷偷看

年轻人你不讲武德,耗子尾汁~~~ 总结就是为了形成自己的js知识网,提升自己,加油! 开始干 1、介绍js的基本数据类型   答: Undefined、Null、Boolean、Number、String 2、js有哪些内置对象?  答&…

大前端JS部分基础面试题(含答案)

1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型:Undefined、Null、Boolean、Number、String 值类型:数值、布尔值、null、undefined。 引用类型:对象、数组、函数。 堆栈数据结构:是一种支…

Js面试题__附答案

1、什么是JavaScript?(这是基本题,对很多程序员来说也是送分题!) JavaScript是客户端和服务器端脚本语言,可以插入到HTML页面中,并且是目前较热门的Web开发语言。同时,JavaScript也…

js 变量及作用域经典面试题

function Foo() {getName function () { alert (1); };return this; } Foo.getName function () { alert (2);}; Foo.prototype.getName function () { alert (3);}; var getName function () { alert (4);}; function getName() { alert (5);}//请写出以下输出结果&#x…

前端面试题集锦——JavaScript

JavaScript 栈和队列的区别? 栈的插入和删除操作都是在一端进行的,而队列的操作却是在两端进行的。 队列先进先出,栈先进后出。 栈只允许在表尾一端进行插入和删除,而队列只允许在表尾一端进行插入,在表头一端进行删除 栈和…

收集的面试题 js面试题

题库推荐网址:https://github.com/FEGuideTeam/FEGuide/tree/master/javascript%E9%97%AE%E9%A2%98 第1题: ## JavaScript 由以下三部分组成:1. ECMAScript(核心):JavaScript 语言基础2. DOM(文档对象模…

JS闭包+常见面试题

scope作用域 、Closure闭包对象 可以借助chrome调式工具查看闭包对象 注意:function声明存在变量提升,所以22行已经存在闭包对象了; 闭包产生的条件: 函数嵌套;嵌套的内部函数引用了外部函数的变量才会产生闭包对象…

前端面试题汇总(含答案)(JS篇)

主要自用,持续更新,相同类型的题目尽量放在了一起,参考的实在太多了就没有列出,侵权烦请联系删除。提示:自动生成的目录在页面右边---------->>>>>>>>>>>>>>>> Js的…