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机制;
五、作业行列
前面的机制不论如何折腾,有一点是不会变的。它们都在中止上下文中。什么意思?阐明它们不行挂起。并且由所以串行履行,因而只需有一个处理时刻较长,则会导致其他中止呼应的推迟。为了完结这些不行能完结的使命,所以呈现了作业行列。作业行列说白了便是一组内核线程,作为中止看护线程来运用。多个中止能够放在一个线程中,也能够每个中止分配一个线程。
作业行列对线程作了封装,运用起来更便利。
由于作业行列是线程,所以咱们能够运用一切能够在线程中运用的办法。
Tasklet其实也纷歧定是在中止上下文中履行,它也有或许在线程中履行。
假设中止数量许多,并且这些中止都是自启动型的(中止处理函数会导致新的中止发生),则有或许cpu一向在这里履行中止处理函数,会导致用户进程永久得不到调度时刻。
为了防止这种状况,linux发现中止数量过多时,会把剩余的中止处理放到一个独自的线程中去做,便是ksofTIrqd线程。这样又确保了中止不多时的呼应速度,又确保了中止过多时不会把用户进程饿死。
问题是咱们不能确保咱们的tasklet或软中止处理函数必定会在线程中履行,所以仍是不能运用进程才干用的一些办法,如抛弃调度、长延时等。
六、运用办法总结
Request_irq挂的中止函数要尽量简略,只做有必要在屏蔽中止状况下要做的作业。
中止的其他部分都在下半部中完结。
软中止的运用准则很简略,永久不必。它乃至都不算是一种正是的中止处理机制,而仅仅tasklet的完结根底。
作业行列也要少用,假设不是有必要要用到线程才干用的某些机制,就不要运用作业行列。其实关于中止来说,仅仅对中止进行简略的处理,大部分作业是在驱动程序中完结的。所以有什么必要非运用作业行列呢?
除了上述状况,就要运用tasklet。
即使是下半部,也仅仅作有必要在中止中要做的作业,如保存数据等,其他都交给驱动程序去做。