前言:
录视频估计又得花半天;
真怀念以前简单粗暴的生活啊:
拿起话筒就录视频,
先画好图不需要的
文档不存在的
真是洒脱.....
现在,要写文档,又要画流程图,十几、二十分钟的视频,
真是沤心沥血做出来的,
各位,别浪费了,欢迎享受
分为7点:
-
Linux对中断的扩展:硬件中断,软件中断
-
中断处理原则1:不能嵌套
-
中断处理原则2:越快越好
-
要处理的事情实在太多:拆分为:上半部,下半部
-
下半部的事情耗时不是太长:tasklet
-
下半部要做的事情太多并且很复杂:工作队列
-
新技术:threaded irq
从2005年我接触Linux到现在15年了,Linux中断系统的变化并不大。比较重要的就是引入了threaded irq:使用内核线程来处理中断。
Linux系统中有硬件中断,也有软件中断。
对硬件中断的处理有2个原则:不能嵌套,越快越好。
参考资料:
https://blog.csdn.net/myarrow/article/details/9287169
01
Linux对中断的扩展:硬件中断、软件中断
Linux系统把中断的意义扩展了,对于按键中断等硬件产生的中断,称之为“硬件中断”(hard irq)。每个硬件中断都有对应的处理函数,比如按键中断、 卡中断的处理函数肯定不一样。
为方便理解,你可以先认为对硬件中断的处理是用数组来实现的,数组里存放的是函数指针:
注意:上图是简化的,Linux中这个数组复杂多了。
问题来了:
a. 软件中断何时生产strong>
由软件决定,对于X 软件中断,只需要把它的flag设置为1就表示发生了该中断。
b. 软件中断何时处理strong>
软件中断嘛,并不是那么十万火急,有空再处理它好了。
什么时候有空让它一直等吧p>
Linux系统中,各种硬件中断频繁发生,至少定时器中断每10ms发生一次,那取个巧p>
在处理写硬件中断后,再去处理软件中断么办!
有哪些软件中断p>
查内核源码include/linux/interrupt.h
怎么设置软件中断的处理函数:
在handler函数中,代码尽可能高效。
但是,处理某个中断要做的事情就是很多,没办法加快。比如对于按键中断,我们需要等待几十毫秒消除机械抖动。难道要在handler中等待吗计算机来说,这可是一个段很长的时间。
怎么办p>
04
要处理的事情实在太多,拆分为:上半部、下半部
当一个中断要耗费很多时间来处理时,它的坏处是:在这段时间内,其他中断无法被处理。换句话说,在这段时间内,系统是关中断的。
如果某个中断就是要做那么多事,我们能不能把它拆分成两部分:紧急的、不紧急的p>
在handler函数里只做紧急的事,然后就重新开中断,让系统得以正常运行;那些不紧急的事,以后再处理,处理时是开中断的。
写字太多,不如贴代码,代码一目了然:
假设硬件中断A的上半部函数为irq_top_half_A,下半部为irq_bottom_half_A。
使用情景化的分析,才能理解上述代码的精华。
a. 硬件中断A处理过程中,没有其他中断发生:
一开始,preempt_count = 0;
上述流程图①~⑨依次执行,上半部、下半部的代码各执行一次。
b. 硬件中断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次,但是下半部代码只执行了一次。
所以,同一个中断的上半部、下半部,在执行时是多对一的关系。
c. 硬件中断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的下半部。
所以,多个中断的下半部,是汇集在一起处理的。
总结:
a. 中断的处理可以分为上半部,下半部
b. 中断上半部,用来处理紧急的事,它是在关中断的状态下执行的
c. 中断下半部,用来处理耗时的、不那么紧急的事,它是在开中断的状态下执行的
d. 中断下半部执行时,有可能会被多次打断,有可能会再次发生同一个中断
e. 中断上半部执行完后,触发中断下半部的处理
f. 中断上半部、下半部的执行过程中,不能休眠:中断休眠的话,以后谁来调度进程啊p>
06
下半部要做的事情太多并且很复杂:工作队列
在中断下半部的执行过程中,虽然是开中断的,期间可以处理各类中断。但是毕竟整个中断的处理还没走完,这期间APP是无法执行的。
假设下半部要执行1、2分钟,在这1、2分钟里APP都是无法响应的。
这谁受得了p>
所以,如果中断要做的事情实在太耗时,那就不能用中断下半部来做,而应该用内核线程来做:在中断上半部唤醒内核线程。内核线程和APP都一样竞争执行,APP有机会执行,系统不会卡顿。
这个内核线程是系统帮我们创建的,一般是kworker线程,内核中有很多这样的线程:
b. 要执行这个函数时,把work提交给work queue就可以了:
你可以只提供thread_fn,系统会为这个函数创建一个内核线程。发生中断时,内核线程就会执行这个函数。
说你懒是开玩笑,内核开发者也不会那么在乎懒人。
以前用work来线程化的处理内核,一个worker线程只能由一个CPU执行,多个中断的work都由同一个worker线程来处理,在单CPU系统中也只能忍着了。但是在SMP系统中,明明有那么多CPU空着,你偏偏让多个中断挤在这个CPU上p>
新技术threaded irq,为每一个中断都创建一个内核线程;多个中断的内核线程可以分配到多个CPU上执行,这提高了效率。
☆ END ☆
扫码或长按关注
回复「 加群 」进入技术群聊
文章知识点与官方知识档案匹配,可进一步学习相关知识CS入门技能树Linux入门初识Linux25019 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!