以下的语句都是摘自网络上的资料,自己再综合总结一下。

Linux的中断处理遵循了“重要的事情,马上做。不重要的事情,推后做”。

 

MIPS平台下的do_IRQ处理函数。

   1:  void __irq_entry do_IRQ(unsigned int irq)
   2:  {
   3:      irq_enter();
   4:      __DO_IRQ_SMTC_HOOK(irq);
   5:      generic_handle_irq(irq);
   6:      irq_exit();
   7:  }

 

MIPS平台下的generic_handle_irq经过层层调用,会调用对应模块通过request_irq函数注册的中断处理函数。

      一般情况下,中断处理函数是在关中断的情况下运行的,为了提高效率,尽量减少关中断的时间,于是有了soft_irq机制,把一部分不需要在关中断情况下执行的代码放在中断外面执行。具体就是调用raise_softirq去设置一个软中断,由open_softirq来注册对应的软中断处理程序,用来处理一些不太紧急的中断处理程序。

在软中断机制中,为每个CPU维护了一个若干位的掩码集,每位掩码代码一个中断号,每位中断号于raise_softirq绑定的中断号相对应。

中断有其对应的优先级,每个CPU处理属于自己的中断。在软中断处理函数中开中断进行处理。

实际上,软中断很少直接使用,由tasklet机制来调用软中断。实际中,在进入中断处理程序后,在完成关中断的部分,调用tasklet_schedule/tasklet_hi_schedule标记一个tasklet,中断处理程序结束。后面的工作由HI_SOFTIRQ/TASKLET_SOFTIRQ对应的软中断处理程序去处理被标记的tasklet。

softirq<---->每个CPU,每个CPU处理自己的softirq(可重入函数,可能在多个CPU上同时运行),常用于时钟中断处理过程和网络收发处理过程。

tasklet是在多个CPU间被串行化执行,处理函数不必考虑可重入的问题。

CPU中断处理完成后,需要恢复之前保存在栈上的寄存器信息,恢复中断之前的运行状态。

softirq tasklet workqueue
轮询所有中断(限制软中断为32个) 无差别队列机制,有中断时才执行
效率比softirq高,支持SMP,无数量限制
一组内核线程,作为中断守护线程来使用
尽量不用 推荐使用 要用到线程才能用到的某些机制时,推荐使用。

softirq —> tasklet —>workqueue

轮训处理所有软中断

可能存在的两方面的问题:

  1. 连续的低优先的中断可能持续占有CPU,而高优先的某些进程则无法获得CPU。
  2. 中断处理的整个阶段,不能调用可能导致睡眠的函数(信号量,分配内存,阻塞式IO申请等等)

 

对与第一个问题:

    1. 新版的Linux内核增加的ksoftirqd的内核线程。如果持续处理的softirq超过了一定数量,则结束中断处理程序,然后唤醒ksoftirq来继续处理。
    2. linux内核提供了工作队列机制来解决上述问题,workqueue。定义一个workqueue结构(包含了处理函数),在中断处理的过程中,调用schedule_work函数,work便加入到workqueue中,等待处理。工作队列有自己的处理线程,这些work被推迟到这些线程中处理,处理过程只可能发生在这些工作线程中,因此,加入到工作队列中的处理函数可以睡眠。