ITPub博客

首页 > > > Linux 中断?这篇文章帮你分析原理及应对方式~

Linux 中断?这篇文章帮你分析原理及应对方式~

作者:u_453e1a12781dea 时间:2017-08-21 09:40:42 0 删除 编辑
点击上方“CU技术社区”一起玩耍哦~

Tasklet 作为一种新机制,显然可以承担更多的优点。正好这时候 SMP 越来越火了,因此又在 tasklet 中加入了 SMP 机制,保证同种中断只能在一个 cpu 上执行。在软中断时代,显然没有这种考虑。因此同一种中断可以在两个 cpu 上同时执行,很可能造成冲突。


Linux 中断下半部处理有三种方式:软中断、tasklet、工作队列。


曾经有人问我为什么要分这几种,该怎么用。当时用书上的东西蒙混了过去,但是自己明白自己实际上是不懂的。最近有时间了,于是试着整理一下 linux 的中断处理机制,目的是起码从原理上能够说得通。


最简单的中断机制


最简单的中断机制就是像芯片手册上讲的那样,在中断向量表中填入跳转到对应处理函数的指令,然后在处理函数中实现需要的功能。类似下图:

这种方式在原来的单片机课程中常常用到,一些简单的单片机系统也是这样用。

它的好处很明显,简单,直接。

下半部

中断处理函数所作的第一件事情是什么?答案是屏蔽中断(或者是什么都不做,因为常常是如果不清除 IF 位,就等于屏蔽中断了),当然只屏蔽同一种中断。之所以要屏蔽中断,是因为新的中断会再次调用中断处理函数,导致原来中断处理现场的破坏。即,破坏了 interrupt context。

随着系统的不断复杂,中断处理函数要做的事情也越来越多,多到都来不及接收新的中断了。于是发生了中断丢失,这显然不行,于是产生了新的机制:分离中断接收与中断处理过程。中断接收在屏蔽中断的情况下完成;中断处理在时能中断的情况下完成,这部分被称为中断下半部。


从上图中看,只看 int0 的处理。Func0 为中断接收函数。中断只能简单的触发 func0,而 func0 则能做更多的事情,它与 funcA 之间可以使用队列等缓存机制。当又有中断发生时,func0 被触发,然后发送一个中断请求到缓存队列,然后让 funcA 去处理。

由于 func0 做的事情是很简单的,所以不会影响 int0 的再次接收。而且在 func0 返回时就会使能 int0,因此 funcA 执行时间再长也不会影响 int0 的接收。

软中断


下面看看 linux 中断处理。作为一个操作系统显然不能任由每个中断都各自为政,统一管理是必须的。

我们不可中断部分的共同部分放在函数 do_IRQ 中,需要添加中断处理函数时,通过 request_irq 实现。下半部放在 do_softirq 中,也就是软中断,通过 open_softirq 添加对应的处理函数。


tasklet

旧事物跟不上历史的发展时,总会有新事物出现。

随着中断数的不停增加,软中断不够用了,于是下半部又做了进化。

软中断用轮询的方式处理。假如正好是最后一种中断,则必须循环完所有的中断类型,才能最终执行对应的处理函数。显然当年开发人员为了保证轮询的效率,于是限制中断个数为 32 个。

为了提高中断处理数量,顺道改进处理效率,于是产生了 tasklet 机制。

Tasklet 采用无差别的队列机制,有中断时才执行,免去了循环查表之苦。


总结下 tasklet 的优点:
(1)无类型数量限制;
(2)效率高,无需循环查表;
(3)支持 SMP 机制;

工作队列


前面的机制不论如何折腾,有一点是不会变的。它们都在中断上下文中。什么意思?说明它们不可挂起。而且由于是串行执行,因此只要有一个处理时间较长,则会导致其他中断响应的延迟。为了完成这些不可能完成的任务,于是出现了工作队列。工作队列说白了就是一组内核线程,作为中断守护线程来使用。多个中断可以放在一个线程中,也可以每个中断分配一个线程。


工作队列对线程作了封装,使用起来更方便。

因为工作队列是线程,所以我们可以使用所有可以在线程中使用的方法。


asklet 其实也不一定是在中断上下文中执行,它也有可能在线程中执行。

假如中断数量很多,而且这些中断都是自启动型的(中断处理函数会导致新的中断产生),则有可能 cpu 一直在这里执行中断处理函数,会导致用户进程永远得不到调度时间。
为了避免这种情况,linux 发现中断数量过多时,会把多余的中断处理放到一个单独的线程中去做,就是 ksoftirqd 线程。这样又保证了中断不多时的响应速度,又保证了中断过多时不会把用户进程饿死。

问题是我们不能保证我们的 tasklet 或软中断处理函数一定会在线程中执行,所以还是不能使用进程才能用的一些方法,如放弃调度、长延时等。

使用方式总结

Request_irq 挂的中断函数要尽量简单,只做必须在屏蔽中断情况下要做的事情。

中断的其他部分都在下半部中完成。

软中断的使用原则很简单,永远不用。它甚至都不算是一种正是的中断处理机制,而只是 tasklet 的实现基础。

工作队列也要少用,如果不是必须要用到线程才能用的某些机制,就不要使用工作队列。其实对于中断来说,只是对中断进行简单的处理,大部分工作是在驱动程序中完成的。所以有什么必要非使用工作队列呢?

除了上述情况,就要使用 tasklet。

即使是下半部,也只是作必须在中断中要做的事情,如保存数据等,其他都交给驱动程序去做。


与 100 + 技术大牛面对面

SACC2017

作为国内最受欢迎的架构师盛会,2017 第九届中国系统架构师大会 (SACC) 将于将于 2017 年 10 月 19-21 日在北京新云南皇冠假日酒店震撼来袭。


大会以 “云智未来” 为主题,云集国内外顶级专家,围绕云计算、人工智能、大数据、移动互联网、产业应用等热点领域展开技术探讨与交流。本届大会共设置 2 大主会场,18 个技术专场;邀请来自互联网、金融、制造业、电商等多个领域,100 余位技术专家及行业领袖来分享他们的经验;并将吸引 4000 + 人次的系统运维、架构师及 IT 决策人士参会,为他们提供最具价值的交流平台。

点击“阅读原文”与100+技术大牛面对面,立享购票7.8折优惠~

原文作者:;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-07-17

  • 博文量
    1982
  • 访问量
    17892