新闻资讯
Group news
青岛广盛源肥业有限公司    您的位置: 首页  >  新闻资讯  >  正文

Linux中断(interrupt)子系统之一:软件中断(softIRQ)

2019年10月11日 文章来源:网络整理 热度:80℃ 作者:刘英

软件中断(softIRQ)是内核提供的一种延迟执行机制,它完全由软件触发,虽然说是延迟机制,实际上,在大多数情况下,它与普通进程相比,能得到更快的响应时间。软中断也是其他一些内核机制的基础,比如tasklet,高分辨率TImer等。

1.  软件中断的数据结构

1.1  struct sofTIrq_acTIon

内核用sofTIrq_action结构管理软件中断的注册和激活等操作,它的定义如下:

[cpp] view plain copy

struct softirq_action  

{  

void    (*action)(struct softirq_action *);  

};  

非常简单,只有一个用于回调的函数指针。软件中断的资源是有限的,内核目前只实现了10种类型的软件中断,它们是:

[cpp] view plain copy

enum  

{  

HI_SOFTIRQ=0,  

TIMER_SOFTIRQ,  

NET_TX_SOFTIRQ,  

NET_RX_SOFTIRQ,  

BLOCK_SOFTIRQ,  

BLOCK_IOPOLL_SOFTIRQ,  

TASKLET_SOFTIRQ,  

SCHED_SOFTIRQ,  

HRTIMER_SOFTIRQ,  

RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */  

NR_SOFTIRQS  

};  

内核的开发者们不建议我们擅自增加软件中断的数量,如果需要新的软件中断,尽可能把它们实现为基于软件中断的tasklet形式。与上面的枚举值相对应,内核定义了一个softirq_action的结构数组,每种软中断对应数组中的一项:

[cpp] view plain copy

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;  

1.2  irq_cpustat_t

多个软中断可以同时在多个cpu运行,就算是同一种软中断,也有可能同时在多个cpu上运行。内核为每个cpu都管理着一个待决软中断变量(pending),它就是irq_cpustat_t:

[cpp] view plain copy

typedef struct {  

unsigned int __softirq_pending;  

} ____cacheline_aligned irq_cpustat_t;  

[cpp] view plain copy

irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;  

__softirq_pending字段中的每一个bit,对应着某一个软中断,某个bit被置位,说明有相应的软中断等待处理。

1.3  软中断的守护进程ksoftirqd

在cpu的热插拔阶段,内核为每个cpu创建了一个用于执行软件中断的守护进程ksoftirqd,同时定义了一个per_cpu变量用于保存每个守护进程的task_struct结构指针:

[cpp] view plain copy

DEFINE_PER_CPU(struct task_struct *, ksoftirqd);  

大多数情况下,软中断都会在irq_exit阶段被执行,在irq_exit阶段没有处理完的软中断才有可能会在守护进程中执行。

2.  触发软中断

要触发一个软中断,只要调用api:raise_softirq即可,它的实现很简单,先是关闭本地cpu中断,然后调用:raise_softirq_irqoff

[cpp] view plain copy

void raise_softirq(unsigned int nr)  

{  

unsigned long flags;  

local_irq_save(flags);  

raise_softirq_irqoff(nr);  

local_irq_restore(flags);  

}  

再看看raise_softirq_irqoff:

[cpp] view plain copy

inline void raise_softirq_irqoff(unsigned int nr)  

{  

__raise_softirq_irqoff(nr);  

......  

if (!in_interrupt())  

wakeup_softirqd();  

}  

先是通过__raise_softirq_irqoff设置cpu的软中断pending标志位(irq_stat[NR_CPUS] ),然后通过in_interrupt判断现在是否在中断上下文中,或者软中断是否被禁止,如果都不成立,则唤醒软中断的守护进程,在守护进程中执行软中断的回调函数。否则什么也不做,软中断将会在中断的退出阶段被执行。

3.  软中断的执行

基于上面所说,软中断的执行既可以守护进程中执行,也可以在中断的退出阶段执行。实际上,软中断更多的是在中断的退出阶段执行(irq_exit),以便达到更快的响应,加入守护进程机制,只是担心一旦有大量的软中断等待执行,会使得内核过长地留在中断上下文中。

3.1  在irq_exit中执行

看看irq_exit的部分:

[cpp] view plain copy

void irq_exit(void)  

{  

......  

sub_preempt_count(IRQ_EXIT_OFFSET);  

if (!in_interrupt() && local_softirq_pending())  

invoke_softirq();  

......  

}  

如果中断发生嵌套,in_interrupt()保证了只有在最外层的中断的irq_exit阶段,invoke_interrupt才会被调用,当然,local_softirq_pending也会实现判断当前cpu有无待决的软中断。代码最终会进入__do_softirq中,内核会保证调用__do_softirq时,本地cpu的中断处于关闭状态,进入__do_softirq:

[cpp] view plain copy

asmlinkage void __do_softirq(void)  

{  

......  

pending = local_softirq_pending();  

__local_bh_disable((unsigned long)__builtin_return_address(0),  

SOFTIRQ_OFFSET);  

restart:  

/* Reset the pending bitmask before enabling irqs */  

set_softirq_pending(0);  

local_irq_enable();  

h = softirq_vec;  

do {  

if (pending & 1) {  

......  

trace_softirq_entry(vec_nr);  

h->action(h);  

trace_softirq_exit(vec_nr);  

......  

}  

h++;  

pending >>= 1;  

} while (pending);  

local_irq_disable();  

pending = local_softirq_pending();  

if (pending && --max_restart)  

goto restart;  

if (pending)  

wakeup_softirqd();  

lockdep_softirq_exit();  

__local_bh_enable(SOFTIRQ_OFFSET);  

}  

首先取出pending的状态;

禁止软中断,主要是为了防止和软中断守护进程发生竞争;

清除所有的软中断待决标志;

打开本地cpu中断;

循环执行待决软中断的回调函数;

如果循环完毕,发现新的软中断被触发,则重新启动循环,直到以下条件满足,才退出:

没有新的软中断等待执行;

循环已经达到最大的循环次数MAX_SOFTIRQ_RESTART,目前的设定值时10次;

如果经过MAX_SOFTIRQ_RESTART次循环后还未处理完,则激活守护进程,处理剩下的软中断;

推出前恢复软中断;

3.2  在ksoftirqd进程中执行

从前面几节的讨论我们可以看出,软中断也可能由ksoftirqd守护进程执行,这要发生在以下两种情况下:

在irq_exit中执行软中断,但是在经过MAX_SOFTIRQ_RESTART次循环后,软中断还未处理完,这种情况虽然极少发生,但毕竟有可能;

内核的其它代码主动调用raise_softirq,而这时正好不是在中断上下文中,守护进程将被唤醒;

上一篇:你会用VMware虚拟机安装Linux系统?


下一篇:你会在Linux系统中恢复被删除文件?

友情链接
Links