中断、软中断、硬件中断、异常、同步中断、异步中断,这几个概念非常容易混淆,这里对本文使用的中断、软中断、softirq进行描述说明:
1.硬件产生的中断称为中断;(异步中断)
2.int $0x80触发的异常,通常也称为软中断;(同步中断)
3.中断处理一般分为上半部和下半部,下半部机制的软中断称为softirq。
假设进程A进入中断处理,对于1、2两种情况,此时处于中断上下文中,如果调用sleep,A首先会由run queue中删除,然后再进行schedule,但是schedule完了后,永远无法再回到sleep后的过程了,因为中断自身并不是一个调度实体(task上记录进程上下文,但不会保存中断上下文)。
对于3,这里分两种情况讨论:
a)通常内核处理完中断处理程序(上半部)后,马上就会调用do_softirq,此时仍处于中断上下文中,不能sleep;
b)对于大量中断出现的场景,内核会唤醒ksoftirqd/n来处理softirq,它处于ksoftirqd/n的上下文中,此时我认为是可以sleep的。
但是通过ksoftirqd/n运行softirq仅仅是softirq处理的特殊情况,softirq必然会运行在a)这种场景下,那么softirq必然不能sleep。
如果需要在下半部中sleep,可以使用work queue机制,任务运行在events/n的上下文中,可以进行调度。
参考阅读:
《Linux内核设计与实现》
https://www.quora.com/Why-cant-you-sleep-in-an-interrupt-handler-in-the-Linux-kernel-Is-this-true-of-all-OS-kernels