SOFTIRQ 上下文中的抢占
Preemption among SOFTIRQ context
我的系统配置如下;
- SMP平台(但我只关注本地CPU)和Preemption off
- ISR A -> raise_softirq(1)
- ISR B -> raise_softirq(2)
当 SOFTIRQ 1 为 运行 时,中断 B 到来,然后 ISR B 启动。
当 irq_exit() 发生在 ISR B 时,它会调用 softirq。因此,它将安排 SOFTIRQ 2(不处理被中断的 SOFTIRQ 1)。
这个说法正确吗?
另一个问题。此时,如果 SOFTIRQ 1 禁用 "bottom_half",我们检测 bottom half 的地方被禁用并跳过 SOFTIRQ 2 的执行?
提前致谢!
也许你混淆了SOFTIRQ和HARDIRQ。 Linux内核中的Softirq是IRQ处理中的"bottom_half",由任务调度器调度执行以处理延迟的IRQ处理。并且在此处理过程中,它可以潜在地处理多个延迟 IRQ 处理,例如您的情况下的 IRQ A 和 IRQ B。
但是如果有任何IRQ进入系统,它会触发ISR handler,并没有立即触发任何SOFTIRQ,只是被安排在以后处理,而不是"invoke" 正如你的措辞所说。 (即,所有硬件 IRQ 处理程序都不应该调用 raise_softirq(),而是安排一个处理程序来处理 IRQ)
总而言之,对于您的场景:
ISR B 结束后,它可能会提交 SOFTIRQ B 供以后处理 - 但它不会调用 raise_softirq()。但是由于SOFTIRQ A在中途被拦截,任何硬件中断后它都会继续之前的最后任务,所以SOFTIRQ A会执行到完成。
详述raise_softirq()内部,调用raise_softirq_irqoff():
inline void raise_softirq_irqoff(unsigned int nr)
{
__raise_softirq_irqoff(nr);
/*
* If we're in an interrupt or softirq, we're done
* (this also catches softirq-disabled code). We will
* actually run the softirq once we return from
* the irq or softirq.
*
* Otherwise we wake up ksoftirqd to make sure we
* schedule the softirq soon.
*/
if (!in_interrupt())
wakeup_softirqd();
}
正如评论所说,如果你在 softirq A 中并且 IRQ B 进来,IRQ B 处理将结束 - 在完成当前 SOFTIRQ A 后重新运行。
为了强调并非所有硬件都调用"raise_softirq()",搜索linux内核得到以下结果(none来自硬件,来自"drivers"分支):
并且在网络 IRQ 处理程序中 - napi_schedule() 被调用。 (通常在所有驱动程序 IRQ 处理程序中搜索 "sched")。以下来自drivers/net/usb/r8152.c:
我的系统配置如下;
- SMP平台(但我只关注本地CPU)和Preemption off
- ISR A -> raise_softirq(1)
- ISR B -> raise_softirq(2)
当 SOFTIRQ 1 为 运行 时,中断 B 到来,然后 ISR B 启动。 当 irq_exit() 发生在 ISR B 时,它会调用 softirq。因此,它将安排 SOFTIRQ 2(不处理被中断的 SOFTIRQ 1)。
这个说法正确吗?
另一个问题。此时,如果 SOFTIRQ 1 禁用 "bottom_half",我们检测 bottom half 的地方被禁用并跳过 SOFTIRQ 2 的执行? 提前致谢!
也许你混淆了SOFTIRQ和HARDIRQ。 Linux内核中的Softirq是IRQ处理中的"bottom_half",由任务调度器调度执行以处理延迟的IRQ处理。并且在此处理过程中,它可以潜在地处理多个延迟 IRQ 处理,例如您的情况下的 IRQ A 和 IRQ B。
但是如果有任何IRQ进入系统,它会触发ISR handler,并没有立即触发任何SOFTIRQ,只是被安排在以后处理,而不是"invoke" 正如你的措辞所说。 (即,所有硬件 IRQ 处理程序都不应该调用 raise_softirq(),而是安排一个处理程序来处理 IRQ)
总而言之,对于您的场景:
ISR B 结束后,它可能会提交 SOFTIRQ B 供以后处理 - 但它不会调用 raise_softirq()。但是由于SOFTIRQ A在中途被拦截,任何硬件中断后它都会继续之前的最后任务,所以SOFTIRQ A会执行到完成。
详述raise_softirq()内部,调用raise_softirq_irqoff():
inline void raise_softirq_irqoff(unsigned int nr)
{
__raise_softirq_irqoff(nr);
/*
* If we're in an interrupt or softirq, we're done
* (this also catches softirq-disabled code). We will
* actually run the softirq once we return from
* the irq or softirq.
*
* Otherwise we wake up ksoftirqd to make sure we
* schedule the softirq soon.
*/
if (!in_interrupt())
wakeup_softirqd();
}
正如评论所说,如果你在 softirq A 中并且 IRQ B 进来,IRQ B 处理将结束 - 在完成当前 SOFTIRQ A 后重新运行。
为了强调并非所有硬件都调用"raise_softirq()",搜索linux内核得到以下结果(none来自硬件,来自"drivers"分支):
并且在网络 IRQ 处理程序中 - napi_schedule() 被调用。 (通常在所有驱动程序 IRQ 处理程序中搜索 "sched")。以下来自drivers/net/usb/r8152.c: