Linux驱动开发基础__Linux 系统对中断处理的演进

news2024/11/23 8:11:44

目录

1  Linux 对中断的扩展:硬件中断、软件中断 

2  中断处理原则 1:不能嵌套

3  中断处理原则 2:越快越好

4 要处理的事情实在太多,拆分为:上半部、下半部 

5 下半部要做的事情耗时不是太长:tasklet

6 下半部要做的事情太多并且很复杂:工作队列 

7 新技术:threaded irq 


Linux 中断系统的变化并不大。比较重要的就是引入了 threaded irq:使用内核线程来处理中断。

Linux 系统中有硬件中断,也有软件中断。对硬件中断的处理有 2 个原则:不能嵌套,越快越好。

1  Linux 对中断的扩展:硬件中断、软件中断 

 Linux 系统把中断的意义扩展了,对于按键中断等硬件产生的中断,称之为“硬件中断”(hard irq)。每个硬件中断都有对应的处理函数,比如按键中断、网卡中断的处理函数肯定不一样。 
为方便理解,你可以先认为对硬件中断的处理是用数组来实现的,数组里存放的是函数指针: 

 注意:上图是简化的,Linux 中这个数组复杂多了。 
当发生 A 中断时,对应的 irq_function_A 函数被调用。硬件导致该函数被调用。 
相对的,还可以人为地制造中断:软件中断(soft irq),如下图所示: 

 注意:上图是简化的,Linux 中这个数组复杂多了。 
问题来了: 
软件中断何时生产? 
由软件决定,对于 X 号软件中断,只需要把它的 flag 设置为 1 就表示发生了该中断。 
软件中断何时处理? 
软件中断嘛,并不是那么十万火急,有空再处理它好了。 什么时候有空?不能让它一直等吧? 
Linux 系统中,各种硬件中断频繁发生,至少定时器中断每 10ms 发生一次,那取个巧? 在处理完硬件中断后,再去处理软件中断?就这么办! 
有哪些软件中断? 
查内核源码 include/linux/interrupt.h 

 怎么触发软件中断?最核心的函数是 raise_softirq,简单地理解就是设置 softirq_veq[nr]的标记位:

 怎么设置软件中断的处理函数: extern  void  open_softirq(int  nr,  void  (*action)  (struct 
soft_action*)); 

 后面讲到的中断下半部 tasklet 就是使用软件中断实现的。 

2  中断处理原则 1:不能嵌套

官方资料:中断处理不能嵌套 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e58aa3d2d0cc 
中断处理函数需要调用 C 函数,这就需要用到栈。 
⚫  中断 A 正在处理的过程中,假设又发生了中断 B,那么在栈里要保存 A 的现
场,然后处理 B。 
⚫  在处理 B 的过程中又发生了中断 C,那么在栈里要保存 B 的现场,然后处理
C。 
如果中断嵌套突然暴发,那么栈将越来越大,栈终将耗尽。 所以,为了防止这种情况发生,也是为了简单化中断的处理,在 Linux 系统上中断无法嵌套:即当前中断 A 没处理完之前,不会响应另一个中断 B(即使它的优先级更高)。 

3  中断处理原则 2:越快越好

妈妈在家中照顾小孩时,门铃响起,她开门取快递:这就是中断的处理。她
取个快递敢花上半天吗?不怕小孩出意外吗? 
同理,在 Linux 系统中,中断的处理也是越快越好。 在单芯片系统中,假设中断处理很慢,那应用程序在这段时间内就无法执行:系统显得很迟顿。

在 SMP 系统中,假设中断处理很慢,那么正在处理这个中断的 CPU 上的其他
线程也无法执行。 在中断的处理过程中,该 CPU 是不能进行进程调度的,所以中断的处理要越快越好,尽早让其他中断能被处理──进程调度靠定时器中断来实现。 在 Linux 系统中使用中断是挺简单的,为某个中断 irq 注册中断处理函数
handler,可以使用 request_irq 函数:

 在 handler 函数中,代码尽可能高效。 但是,处理某个中断要做的事情就是很多,没办法加快。比如对于按键中断,我们需要等待几十毫秒消除机械抖动。难道要在 handler 中等待吗?对于计算
机来说,这可是一个段很长的时间。 怎么办? 

4 要处理的事情实在太多,拆分为:上半部、下半部 

当一个中断要耗费很多时间来处理时,它的坏处是:在这段时间内,其他中断无法被处理。换句话说,在这段时间内,系统是关中断的。 
如果某个中断就是要做那么多事,我们能不能把它拆分成两部分:紧急的、不紧急的? 
在 handler 函数里只做紧急的事,然后就重新开中断,让系统得以正常运行;那些不紧急的事,以后再处理,处理时是开中断的。 

中断下半部的实现有很多种方法,讲 2 种主要的:tasklet(小任务)、work queue(工作队列)。  

5 下半部要做的事情耗时不是太长:tasklet

假设我们把中断分为上半部、下半部。发生中断时,上半部下半部的代码何时、如何被调用? 
当下半部比较耗时但是能忍受,并且它的处理比较简单时,可以用 tasklet来处理下半部。tasklet 是使用软件中断来实现。 

 写字太多,不如贴代码,代码一目了然:

 使用流程图简化一下:

 假 设 硬 件 中 断 A 的 上 半 部 函 数 为 irq_top_half_A , 下 半 部 为
irq_bottom_half_A。 
使用情景化的分析,才能理解上述代码的精华。 
⚫  硬件中断 A 处理过程中,没有其他中断发生: 一开始,preempt_count = 0;上述流程图①~⑨依次执行,上半部、下半部的代码各执行一次。  
⚫  硬件中断 A 处理过程中,又再次发生了中断 A: 
一开始,preempt_count = 0; 
执行到第⑥时,一开中断后,中断 A 又再次使得 CPU 跳到中断向量表。 
注意:这时 preempt_count 等于 1,并且中断下半部的代码并未执行。 
CPU 又从①开始再次执行中断 A 的上半部代码: 
在第①步 preempt_count 等于 2; 
在第③步 preempt_count 等于 1; 
在第④步发现 preempt_count 等于 1,所以直接结束当前第 2 次中断的处
理; 
注意:重点来了,第 2 次中断发生后,打断了第一次中断的第⑦步处理。当第 2
次中断处理完毕,CPU 会继续去执行第⑦步。 
可以看到,发生 2 次硬件中断 A 时,它的上半部代码执行了 2 次,但是下半
部代码只执行了一次。 
所以,同一个中断的上半部、下半部,在执行时是多对一的关系。 
⚫  硬件中断 A 处理过程中,又再次发生了中断 B: 
一开始,preempt_count = 0; 
执行到第⑥时,一开中断后,中断 B 又再次使得 CPU 跳到中断向量表。 
注意:这时 preempt_count 等于 1,并且中断 A 下半部的代码并未执行。 
CPU 又从①开始再次执行中断 B 的上半部代码: 
在第①步 preempt_count 等于 2; 
在第③步 preempt_count 等于 1; 
在第④步发现 preempt_count 等于 1,所以直接结束当前第 2 次中断的处
理; 
注意:重点来了,第 2 次中断发生后,打断了第一次中断 A 的第⑦步处理。当第
2 次中断 B 处理完毕,CPU 会继续去执行第⑦步。 
在第⑦步里,它会去执行中断 A 的下半部,也会去执行中断 B 的下半部。 
所以,多个中断的下半部,是汇集在一起处理的。 
总结: 

  •   中断的处理可以分为上半部,下半部 
  •   中断上半部,用来处理紧急的事,它是在关中断的状态下执行的 
  •   中断下半部,用来处理耗时的、不那么紧急的事,它是在开中断的状态下执行的 
  •   中断下半部执行时,有可能会被多次打断,有可能会再次发生同一个中断 
  •   中断上半部执行完后,触发中断下半部的处理 
  •  中断上半部、下半部的执行过程中,不能休眠:中断休眠的话,以后谁来调度进程啊? 

6 下半部要做的事情太多并且很复杂:工作队列 

在中断下半部的执行过程中,虽然是开中断的,期间可以处理各类中断。但是毕竟整个中断的处理还没走完,这期间 APP 是无法执行的。 
假设下半部要执行 1、2 分钟,在这 1、2 分钟里 APP 都是无法响应的。 
这谁受得了?所以,如果中断要做的事情实在太耗时,那就不能用软件中断来做,而应该用内核线程来做:在中断上半部唤醒内核线程。内核线程和 APP 都一样竞争执行,APP 有机会执行,系统不会卡顿。 
这个内核线程是系统帮我们创建的,一般是 kworker 线程,内核中有很多这
样的线程: 

 kworker 线程要去“工作队列”(work queue)上取出一个一个“工作”(work),来执行它里面的函数。 
那我们怎么使用 work、work queue 呢?

创建 work: 
你得先写出一个函数,然后用这个函数填充一个 work 结构体。比如: 

 要执行这个函数时,把 work 提交给 work queue 就可以了:


上述函数会把 work 提供给系统默认的 work  queue:system_wq,它是一个队列。 谁来执行 work 中的函数? 不用我们管,schedule_work 函数不仅仅是把 work 放入队列,还会把kworker 线程唤醒。此线程抢到时间运行时,它就会从队列中取出 work,执行里面的函数。 谁把 work 提交给 work queue? 在中断场景中,可以在中断上半部调用 schedule_work 函数。

 总结: 

  • 很耗时的中断处理,应该放到线程里去
  • 可以使用 work、work queue 
  • 在中断上半部调用 schedule_work 函数,触发 work 的处理 
  • 既然是在线程中运行,那对应的函数可以休眠。

  7 新技术:threaded irq 

使用线程来处理中断,并不是什么新鲜事。使用 work 就可以实现,但是需要定义 work、调用 schedule_work,好麻烦啊。于是内核提供了这样一个函数。

 你可以只提供 thread_fn,系统会为这个函数创建一个内核线程。发生中断时,内核线程就会执行这个函数。 
以前用 work 来线程化地处理中断,一个 worker 线程只能由一个 CPU 执行,多个中断的 work 都由同一个 worker 线程来处理,在单 CPU 系统中也只能忍着了。但是在 SMP 系统中,明明有那么多 CPU 空着,你偏偏让多个中断挤在这个CPU 上? 
新技术 threaded irq,为每一个中断都创建一个内核线程;多个中断的内核线程可以分配到多个 CPU 上执行,这提高了效率。 

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

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

相关文章

154. 滑动窗口

文章目录QuestionIdeasCodeQuestion 给定一个大小为 n≤106 的数组。 有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。 你只能在窗口中看到 k 个数字。 每次滑动窗口向右移动一个位置。 以下是一个例子: 该数组为 [1 3 -1 -3 5 3 6 7]&…

知识点滴 - 数据库视图概念

视图是数据库中一个非常简单的概念,写过SQL的人几乎大致了解视图。本文除了在回顾视图的本质及相关操作知识时,会重点阐述它蕴含的分层思想在数据分析工作中的作用。 1,视图的本质与作用 视图是一个数据库中的虚拟表,它的本质是S…

模板特化与static成员初始化

我们知道在 c 的类中&#xff0c;如果有static成员数据&#xff0c;则需要在类外进行定义&#xff0c;而类内那只是声明。这个在类模板中也是一样的&#xff0c;需要在类外进行定义。普通类模板的 static 数据的初始化&#xff0c;如下代码&#xff1a; template <class T&…

SpringBoot在Controller层接收参数的常用方法(超详细)

前言 在工作中&#xff0c;比如要实现一个功能&#xff0c;前端传什么参数&#xff0c;后端的controller层中怎么接收参数 &#xff0c;封装成了什么实体对象&#xff0c;有些参数是在URL上使用&#xff0c;有些参数是在body上使用&#xff0c;service层中做了什么逻辑&#xf…

数据结构(根据王道整理)

数据结构 文章目录数据结构线性结构与非线性结构链表kmp算法栈二叉树完全二叉树二叉树的存储结构二叉树的访问树的深度二叉树的层次遍历由遍历序列构造二叉树已知后序跟中序建立二叉树线索二叉树序言&#xff08;土办法解决找前驱&#xff09;线索二叉树存储结构中序线索二叉树…

几道基础的二叉树、树的题

几道基础的二叉树、树的题LeetCode144.二叉树的前序遍历思路及实现方法一&#xff1a;递归方法二&#xff1a;迭代LeetCode145.二叉树的后序遍历思路及实现方法一&#xff1a;递归方法二&#xff1a;迭代LeetCode94.二叉树的中序遍历思路及实现方法一&#xff1a;递归方法二&am…

数据结构(2)树状数组

活动 - AcWing 参考&#xff1a;《算法竞赛进阶指南》-lyd 目录 一、概念 1.主要功能 2.实现方式 3. 二、例题 1.树状数组和逆序对 2.树状数组和差分 3. 两层差分 4. 结合二分 一、概念 1.主要功能 树状数组可以完成的功能主要有&#xff1a; 维护序列的前缀和单…

pytest-pytest插件之测试覆盖率pytest-cov

简介 测试覆盖率是指项目代码被测试用例覆盖的百分比&#xff0c;使用pytest-cov插件可以统计测试覆盖率 添加链接描述 安装插件pytest-cov pip install pytest-cov用法 基本用法 –cov的参数是要统计代码覆盖率的源码&#xff0c;我将源码放在mysrc中&#xff0c;test_s…

qiankun微应用加载第三方js跨域报错

当我们在qiankun微应用&#xff0c;引入第三方js脚本时会产生跨域问题并报错&#xff0c;看qiankun的解释&#xff1a;常见问题 - qiankunqiankun会把静态资源的加载拦截&#xff0c;改用fetch方式获取资源&#xff0c;所以要求这些资源支持跨域。虽然qiankun也提供了解决方案&…

react面试题--react入门小案例案例

React入门应该是这样的 源码&#xff1a;https://github.com/dansoncut/React-beginner-tutorial-TeacherEgg.git 视频地址&#xff1a;https://www.bilibili.com/video/BV1be411w7iF/?spm_id_from333.337.search-card.all.click&vd_sourceae42119b44d398cd8fe181740c3e…

Java线程的六种状态

前言&#xff1a;其实线程的状态在操作系统的PCB中就对其进行了描述&#xff0c;但是Java中觉得自带的状态并不是特别好&#xff0c;于是引入了线程在Java中的六种状态。 (1) NEW 安排了工作还未行动&#xff0c;即&#xff1a;Thread对象创建出来了&#xff0c;但是内核的PCB…

开源工具 tomcat

Tomcat 封装了很多HTTP的操作&#xff1a;负责解析 HTTP 协议&#xff0c;解析请求数据&#xff0c;并发送响应数据。 官网 download下的which version&#xff1a; Apache Tomcat - Which Version Do I Want? 可以看tomcat对jdk的版本要求。 启动 启动&#xff1a;双击…

【redis6】第六章(新数据类型)

Bitmaps 简介 现代计算机用二进制&#xff08;位&#xff09;作为信息的基础单位&#xff0c; 1个字节等于8位&#xff0c; 例如“abc”字符串是由3个字节组成&#xff0c; 但实际在计算机存储时将其用二进制表示&#xff0c; “abc”分别对应的ASCII码分别是97、 98、 99&am…

SEO优化收徒站外引蜘蛛软件方法

SEO优化收徒站外引蜘蛛软件方法 今天我们讲解站外引蜘蛛的方法&#xff0c;站外引蜘蛛的方法无非就是五个大点。 第一个是搜索引擎的提交&#xff0c;我们通过是百度资源站展或者 360 或者神马头条&#xff0c;搜狗 bin 等等这样的一个搜索引擎去提交我们的链接。 里面主要是…

【css】结构选择器

结构选择器&#xff0c;也称之为组合器选择器&#xff0c;根据它们之间的特定关系来选取元素。CSS 中有四种不同的组合器&#xff1a;后代选择器 (空格)子选择器 (>)相邻兄弟选择器 ()通用兄弟选择器 (~)选择器示例描述element elementdiv p选择 div 元素内部的所有 p 元素e…

仗剑走天涯是梦想,仗键走天涯是坚持

在这信息化、数字化浪潮发展中&#xff0c;人们办公、娱乐、学习、生活都离不开了手机电脑平板等一系列电子设备&#xff0c;互联网行业工作者更是不可避免的需要频繁接触到电脑、键盘、鼠标等设备&#xff0c;今天给大家推荐一款性价比极高的键盘Keychron K3 Pro 一、keychron…

小程序API Promise化

一、 应用场景 小程序页面初始化时&#xff0c;需要去服务端获取token&#xff0c;所带参数在另外两个接口请求中&#xff0c;所写代码可能是这样子的&#xff1a; onLoad(options) {this.getToken() }, getToken() {wx.request({url: 后端API地址1,success: (res) > {//…

_Linux多线程-线程互斥篇

文章目录1. 进程线程间的互斥相关背景概念2. 互斥量mutex3. 互斥量的接口初始化互斥量销毁互斥量互斥量加锁和解锁4. 互斥量---锁静态分配&#xff08;初始化&#xff09;动态分配&#xff08;初始化&#xff09;5. 互斥量实现原理探究6. 总结&#xff1a;1. 进程线程间的互斥相…

【随即森林模型】

随机森林模型的基本原理和代码实现 集成模型简介 集成学习模型是机器学习非常重要的一部分。 集成学习是使用一系列的弱学习器&#xff08;或称之为基础模型&#xff09;进行学习&#xff0c;并将各个弱学习器的结果进行整合从而获得比单个学习器更好的学习效果的一种机器学习…

嵌入式设备中可以使用SQLite3吗?

摘要&#xff1a;数据库是用来存储和管理数据的专用软件&#xff0c;使得管理数据更加安全&#xff0c;方便和高效。数据库对数据的管理的基本单位是表(table)&#xff0c;在嵌入式linux中有时候它也需要用到数据库&#xff0c;听起来好难&#xff0c;其实就是几个函数&#xf…