您的位置 首页 软件

简略剖析linux的中止处理

简单分析linux的中断处理-每个CPU都有响应中断的能力, 每个CPU响应中断时都走相同的流程。 这个流程就是内核提供的中断服务程序。

  最近在研讨异步音讯处理, 忽然想起linux内核的中止处理, 里边由始至终都贯穿戴“重要的事立刻做, 不重要的事推后做”的异步处理思维。 所以收拾一下。

  

  第一阶段--获取中止号

  每个CPU都有呼应中止的才能, 每个CPU呼应中止时都走相同的流程。 这个流程便是内核供给的中止服务程序。

  在进入中止服务程序时, CPU现已主动制止了本CPU上的中止呼应, 由于CPU不能假定中止服务程序是可重入的。

  中止处理程序的第一步要做两件作业:

  1. 将中止号压入栈中; (不同中止号的中止对应不同的中止服务程序进口)

  2. 将当时寄存器信息压入栈中; (以便中止退出时康复)

  明显, 这两步都是不行重入的(假如在保存寄存器值时被中止了, 那么别的的操作很或许就把寄存器给改写了, 现场将无法康复), 所以前面提到的CPU进入中止服务程序时要主动制止中止。

  栈上的信息被作为函数参数, 调用do_IRQ函数。

  第二阶段--中止串行化

  进入do_IRQ函数, 第一步进行中止的串行化处理, 将多个CPU一起产生的某一中止进行串行化。 其办法是假如当时中止处于“履行”状况(标明另一个CPU正在处理相同的中止), 则从头设置它的“触发”符号, 然后当即回来。 正在处理同一中止的那个CPU完结一次处理后, 会再次查看“触发”符号, 假如设置, 则再次触发处理进程。

  所以, 中止的处理是一个循环进程, 每次循环调用handle_IRQ_event来处理中止。

  第三阶段--关中止条件下的中止处理

  进入handle_IRQ_event函数, 调用对应的内核或内核模块经过request_irq函数注册的中止处理函数。

  注册的中止处理函数有个中止开关特点, 一般状况下, 中止处理函数总是在关中止的状况下进行的。 而调用request_irq注册中止处理函数时也能够设置该中止处理函数在开中止的状况下进行, 这种状况比较罕见, 由于这要求中止处理代码有必要是可重入的。 (别的, 这儿假如开中止, 正在处理的这个中止一般也是会被堵塞的。 由于正在处理某个中止的时分, 硬件中止操控器上的这个中止并未被ack, 硬件不会建议下一次相同的中止。)

  中止处理函数的进程或许会很长, 假如整个进程都在关中止的状况下进行, 那么后续的中止将被堵塞很长的时刻。

  所以, 有了soft_irq. 把不行重入的一部分在中止处理程序中(关中止)去完结, 然后调用raise_softirq设置一个软中止, 中止处理程序完毕。 后边的作业将放在soft_irq里边去做。

  第四阶段--开中止条件下的软中止

  上一阶段循环调用完当时一切被触发的中止处理函数后, do_sofTIrq函数被调用, 开端处理软件中止。

  在软中止机制中, 为每个CPU保护了一个若干位的掩码集, 每位掩码代表一个中止号。 在上一阶段的中止处理函数中, 调用raise_sofTIrq设置了对应的软中止, 到了这儿, 软中止对应的处理函数就会被调用(处理函数由open_sofTIrq函数来注册)。

  能够看出, 软中止与中止的模型很相似, 每个CPU有一组中止号, 中止有其对应的优先级, 每个CPU处理归于自己的中止。 最大的不同是开中止与关中止。

  所以, 一个中止处理进程被分成了两部分, 第一部分在中止处理函数里边关中止的进行, 第二部分在软中止处理函数里边开中止的进行。

  由于这一步是在开中止条件下进行的,这儿还或许产生新的中止(中止嵌套),然后新中止对应的中止处理又将开端一个新的第一阶段~第三阶段。在新的这个第三阶段中,或许又会触发新的软中止。可是这个新的中止处理进程并不会进入第四阶段,而是当它发现自己是嵌套的中止时,完结第三阶段之后就会退出了。也便是说,只要第一层中止处理进程会进入第四阶段,嵌套产生的中止处理进程只履行到第三阶段。

  可是嵌套产生的中止处理进程也或许会触发软中止,所以第一层中止处理进程在第四阶段需求是一个循环的进程,需求循环处理嵌套产生的一切软中止。为什么要这样做呢?由于这样能够按软中止触发的次序来履行这些软中止,不然后来的软中止或许就会先履行完结了。

  极点状况下,嵌套产生的软中止或许十分多,悉数处理完或许需求很长的时刻,所以内核会在处理完必定数量的软中止后,将剩余未处理的软中止推给一个叫ksofTIrqd的内核线程来处理,然后完毕本次中止处理进程。

  第五阶段--开中止条件下的tasklet

  实际上, 软中止很少直接被运用。 而第二部分隔中止状况下的进行的处理进程一般是由tasklet机制来完结的。

  tasklet是由软中止引出的, 内核界说了两个软中止掩码HI_SOFTIRQ和TASKLET_SOFTIRQ(两者优先级不同), 这两个掩码对应的软中止处理函数作为进口, 进入tasklet处理进程。

  所以, 在第三阶段的中止处理函数中, 完结关中止的部分后, 然后调用tasklet_schedule/tasklet_hi_schedule符号一个tasklet, 然后中止处理程序完毕。 后边的作业由HI_SOFTIRQ/TASKLET_SOFTIRQ对应的软中止处理程序去处理被符号的tasklet(每个tasklet在其初始化时都设置了处理函数)。

  看上去, tasklet只不过是在softirq的基础上多了一层调用, 其效果是什么呢? 前面说过, softirq是与CPU相对应的, 每个CPU处理自己的softirq. 这些softirq的处理函数需求规划为可重入的, 由于它们或许在多个CPU上一起运转。 而tasklet则是在多个CPU间被串行化履行的, 其处理函数不用考虑可重入的作业。

  可是, softirq究竟仍是要比tasklet少绕点弯路, 所以少量实时性要求相对较高的处理进程仍是在精心规划之后, 直接运用softirq了。 比方: 时钟中止处理进程, 网络发送/接纳处理进程。

  完毕阶段

  CPU接纳到中止今后, 以历以上五个阶段, 中止处理完结。 最终需求康复第一阶段中被保存在栈上的寄存器信息。 中止处理完毕。

  关于调度

  上面的流程中, 还隐含了一个问题, 整个处理进程是持续占有CPU的(除了开中止状况下或许被新的中止打断以外)。 而且, 中止处理的这几个阶段中, 程序不能够让出CPU!

  这是由内核的规划决议的, 中止服务程序没有自己的task结构(即操作系统教科书上说的进程操控块), 所以它不能被内核调度。 通常说一个进程让出CPU, 在之后假如满意某种条件, 内核会经过它的task结构找到它, 并调度其运转。

  这儿或许存在两方面的问题:

  1. 接连的低优先的中止或许持续占有CPU, 而高优先的某些进程则无法取得CPU;

  2. 中止处理的这几个阶段中不能调用或许导致睡觉的函数(包含分配内存);

  关于第一个问题, 较新的linux内核增加了ksoftirqd内核线程, 假如持续处理的softirq超越必定数量, 则完毕中止处理进程, 然后唤醒ksoftirqd, 让它来持续处理。 尽管softirq或许被推后到ksoftirqd内核线程去处理, 可是仍是不能在softirq处理进程中睡觉, 由于不能确保softirq必定在ksoftirqd内核线程中被处理。

  据说在montavista(一种嵌入式实时linux)中, 将内核的中止机制做了修正。 (某些中止的)中止处理进程被赋予了task结构, 能够被内核调度。 处理了上述两个问题。 (montavista的方针是实时性, 这样的做法献身了必定的全体功能。)

  作业行列

  linux基线版别的内核在处理上述问题上, 供给了workqueue机制。

  界说一个work结构(包含了处理函数), 然后在上述的中止处理的几个阶段的某一步中调用schedule_work函数, work便被增加到workqueue中, 等候处理。

  作业行列有着自己的处理线程, 这些work被推迟到这些线程中去处理。 处理进程只或许产生在这些作业线程中, 所以这儿能够睡觉。

  内核默许启动了一个作业行列, 对应一组作业线程events/n(n代表处理器编号, 这样的线程有n个)。 驱动程序能够直接向这个作业行列增加使命。 某些驱动程序还或许会创立并运用归于自己的作业行列.

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/ruanjian/89394.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部