找回密码
 注册
关于网站域名变更的通知
查看: 30|回复: 0
打印 上一主题 下一主题

怎么了解Linux中断处理原理

[复制链接]
  • TA的每日心情
    开心
    2023-5-15 15:14
  • 签到天数: 1 天

    [LV.1]初来乍到

    跳转到指定楼层
    1#
     楼主| 发表于 2024-8-1 17:48 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

    EDA365欢迎您登录!

    您需要 登录 才可以下载或查看,没有帐号?注册

    x

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

    " L3 j4 a) f; M  s% y( U

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

    ) K- f9 `! `2 s5 A- J( Q2 r

    一、最简单的中断机制

    5 ?. i/ P5 T! t% `' ~5 D1 E

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

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


    : E; \0 Z" Q2 g+ a  v5 I- S- g

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


    : [- S$ l) Y' p# J" z, m3 x5 t' O, g

    二、下半部


      R. A0 P. ]: H; K2 @5 I" g

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


    5 q2 T7 z0 j$ ]+ t) E3 r

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

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


    0 r( [5 C/ m2 W8 O7 q: Z

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

    * b3 D% y  {! O' ?6 b- g% H

    三、软中断

    9 B! G9 g2 u" b/ F, _6 H& b; c5 v

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

    5 m, @% H* k6 j6 \

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

    四、tasklet

    4 `# W" _0 P/ }* x! M; T6 [( {6 T

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

    ) g% j; A- O! C! c

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

    0 \8 |: g/ m; k# s2 r; Y

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


    3 b" M# \1 l( U1 q

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

    7 n5 l8 ]- F9 t8 P* i" u9 y8 }

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

    总结下tasklet的优点:

    0 y  d- A6 o7 a0 r7 \4 Y

    (1)无类型数量限制;

    - O5 t0 A6 [% p

    (2)效率高,无需循环查表;


    5 l% |: x4 A7 R3 x9 t. h

    (3)支持SMP机制;

    # X, M# |- c% o9 t% B

    五、工作队列

    0 \% p+ h; J# B6 _# P' a# U: @

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


    : l6 y( f% Q- Z/ i( n! ^

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

    + ?0 N  B0 c" t- w8 R1 G, J

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

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

    6 J) |) T; L: {7 t3 e0 h

    假如中断数量很多,而且这些中断都是自启动型的(中断处理函数会导致新的中断产生),则有可能cpu一直在这里执行中断处理函数,会导致用户进程永远得不到调度时间。


    + d  ]7 I, K6 l- V

    为了避免这种情况,linux发现中断数量过多时,会把多余的中断处理放到一个单独的线程中去做,就是ksoftirqd线程。这样又保证了中断不多时的响应速度,又保证了中断过多时不会把用户进程饿死。


    : J4 [4 t) v3 o

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


    ' N6 y7 W) g9 a8 r( s

    六、使用方式总结


    1 a5 ^1 i) J6 z7 U; a0 H

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


    9 t9 {! V( i$ d0 u$ a2 z* z) d9 a

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


    7 ?6 X+ X  U7 k8 V$ i

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


    . r' _+ |! s" S# q6 R3 j9 `& p( Q) b+ O

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

    % F: N7 S/ C# b! M% J

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

    , Z& {0 Z0 a( j8 |; r9 ?

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


    9 n4 m- v3 q, t6 [' l7 |; _


    # G4 s  ^$ L& a  ?


    : O: ~$ ?+ h' w. f" H0 f; w' q

    % n2 M/ A# W9 W7 I: \
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-8-19 17:19 , Processed in 0.125000 second(s), 26 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表