对这个问题一直很好奇,这里特指的完成硬件中断的处理后去处理软中断的时候,而不是ksoftirqd线程处理软中断的时候。
我们知道,中断退出前会调用irq_exit函数,irq_exit函数一进来就把中断关了(我觉得是为了防止注册的中断处理函数把中断打开的情况),然后最后调用到了invoke_irq()处理软中断,那么调用invoke_irq()的时候,硬件中断是disable的
void irq_exit(void)
{
#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
local_irq_disable();
#else
lockdep_assert_irqs_disabled();
#endif
account_irq_exit_time(current);
preempt_count_sub(HARDIRQ_OFFSET);
if (!in_interrupt() && local_softirq_pending()) //检查是否处于进程上下文中且有pending状态的软中断
invoke_softirq(); //处理软中断
tick_irq_exit();
rcu_irq_exit();
trace_hardirq_exit(); /* must be last! */
}
进入invoke_softirq函数看一下,会调用__do_softirq做进一步的处理。
static inline void invoke_softirq(void)
{
if (ksoftirqd_running(local_softirq_pending()))/*如果本 CPU 上软中断处理进程已经在运行状态了,则直接返回*/
return;
if (!force_irqthreads) {
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
/*
* We can safely execute softirq on the current stack if
* it is the irq stack, because it should be near empty
* at this stage.
*/
__do_softirq();
#else
/*
* Otherwise, irq_exit() is called on the task stack that can
* be potentially deep already. So call softirq in its own stack
* to prevent from any overrun.
*/
do_softirq_own_stack();
#endif
} else {
wakeup_softirqd(); //强制线程化情况,唤醒ksoftirqd内核线程处理
}
}
原来__do_softirq函数进来之后就开启了中断响应,然后处理软中断,软中断处理完成后,又把中断响应关了。
所以,处理softirq的时候,是可以响应硬件中断的。
asmlinkage __visible void __softirq_entry __do_softirq(void)
{
unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
unsigned long old_flags = current->flags;
int max_restart = MAX_SOFTIRQ_RESTART;
struct softirq_action *h;
bool in_hardirq;
__u32 pending;
int softirq_bit;
pending = local_softirq_pending();//获取当前CPU的软中断寄存器__softirq_pending值到局部变量pending。
account_irq_enter_time(current);
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); //增加preempt_count中的softirq域计数,表明当前在软中断上下文中。
in_hardirq = lockdep_softirq_start();
restart:
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0);//清除软中断寄存器__softirq_pending
local_irq_enable();//打开本地中断
******
local_irq_disable(); //关闭本地中断
}