软中断的含义就是模仿硬中断的实现方式,软就是软件模拟的意思。它处于中断的下半部执行,目的是想要使中断上半部快速执行完毕。耗时的一些工作放到下半部去执行。避免丢中断和系统响应慢的问题。
在interrupt.h中定义了软中断号。
enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
#ifdef CONFIG_HIGH_RES_TIMERS
HRTIMER_SOFTIRQ,
#endif
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
};
softirq-daemon会遍历pending的softirq,如果存在,会相应执行对应的action.
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}//注册软中断
如果发现有pending状态,do_softirq会调用__do_softirq函数
asmlinkage void __do_softirq(void)
{
struct softirq_action *h;
__u32 pending;
int max_restart = MAX_SOFTIRQ_RESTART;
int cpu;
pending = local_softirq_pending();
account_system_vtime(current);
__local_bh_disable((unsigned long)__builtin_return_address(0));
trace_softirq_enter();
cpu = smp_processor_id();
restart:
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0);
local_irq_enable();
h = softirq_vec;
do {
if (pending & 1) {
h->action(h); //执行中断处理函数。
rcu_bh_qsctr_inc(cpu);
}
h++;
pending >>= 1;
} while (pending);
local_irq_disable();
pending = local_softirq_pending();
if (pending && --max_restart)
goto restart;
if (pending)
wakeup_softirqd();
trace_softirq_exit();
account_system_vtime(current);
_local_bh_enable();
}
Softirq调用时机
CPU空闲的时候:
void idle_loop(void)
{
for ( ; ; )
{
page_scrub_schedule_work();
default_idle();
do_softirq();
}
}
每次中断返回的时候:
arch/x86/x86_32/entry.S
ENTRY(ret_from_intr)
GET_CURRENT(%ebx)
movl UREGS_eflags(%esp),%eax
movb UREGS_cs(%esp),%al
testl $(3|X86_EFLAGS_VM),%eax
jnz test_all_events
jmp restore_all_xen
test_all_events:
xorl %ecx,%ecx
notl %ecx
cli # tests must not race interrupts
/*test_softirqs:*/
movl VCPU_processor(%ebx),%eax
shl $IRQSTAT_shift,%eax
test %ecx,irq_stat(%eax,1)
jnz process_softirqs
btr $_VCPUF_nmi_pending,VCPU_flags(%ebx)
jc process_nmi
process_softirqs:
sti
call do_softirq
jmp test_all_events
对于XEN虚拟环境,还有两处:
domain_crash_synchronous()->__domain_crash_synchronous()-> do_softirq()
arch_vmx_do_resume()-->hvm_do_resume()->wait_on_xen_event_channel(port, condition)->do_softirq()