linux底层的若干机制之linux下半部处理

Linux网络系统底层机制分析(2

----linux底层的若干机制(续)

3 软中断

下面的内容大都总结自《linux kernel development》。

由于我们希望中断处理函数执行花的时间越短越好,因此,可以把一部分相对不是那么紧急的工作推后执行,这就是下半部的角色。下半部的任务就是执行与中断处理密切相关的但中断处理程序本身不执行的工作。一般来说,中断处理程序完成的任务主要是确认中断,并拷贝数据到内存中,余下的工作便是下半部的事了。

Linux的下半部机制有一个发展的过程,最初是“bottom half---BH”,由于其灵活性不够(静态创建的),存在一定的性能瓶颈,后来引入了任务队列(task queue)以代替BH。但是改善效果不是很明显,在2.3以后,引入了软中断和tasklet,但是仍然保留了task queue

软中断是一组静态定义的接口,定义为:

static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;

struct softirq_action

{

void (*action)(struct softirq_action *);/*使用自结构体作为参数可以适应将来可能的改变*/

void *data;/*可以存放实际会使用到的数据*/

};

Tasklet实际上是一种基于软中断的灵活性强的,动态创建的下半部实现机制。但也有一些不同的地方。一般的软中断可以在所有的处理器上同时执行,即使是两个类型相同的也可以(类型相同,指的是在softirq_vecindex相同),而两个类型不同的tasklet可以在不同的处理器上同时执行(这个好理解),但是相同的tasklet则不行。Tasklet其实是一种在性能和易用性之间寻求平衡的产物(见前一个限制。这样的设计可能是因为softirq的执行机会比较多,并且其优先级比较高,对于一些对执行频率不是要求特别高的重要任务,如果也在每个cpu上都可以同时执行,会造成一些浪费,并且对其他的任务影响也比较大。所以处理他别几个特别高级别的任务,可以选择使用tasklet,达到一种妥协。并且这样不用考虑访问冲突),这样不同的任务都可以找到适合自己的机制,不会造成浪费。性能稍比软中断弱一些,但是由于其可以动态创建,灵活性比较强。

现在内核中用到的软中断个数比较少,tasklet占用的indexTASKLET_SOFTIRQ5。网络接收和发送使用了两个软中断号,NET_TX_SOFTIRQ2NET_RX_SOFTIRQ3

软中断必须先触发(raise_softirq)才能被执行,这实际上就是标记一个全局的标志数字--cpu_pending,在将对应的位置1(为什么只是标识本CPU?),通过下面的代码就可以认识它了。软中断都在一个函数中被调用执行:do_softirq,它检查到pending有未决的软中断(不为零)时,调用__do_softirq,下面来看__do_softirq的执行:

......
restart:

/* Reset the pending bitmask before enabling irqs */

set_softirq_pending(0);/*将本cpu对应的cpu_pending字段置为零,它的值已被保存在pending局部变量中。这样做的目的是避免下面处理中产生的中断打乱它的值*/

local_irq_enable();/*打开中断*/

h = softirq_vec;/*h指向静态全局的软中断数组*/

do {

    if (pending & 1) {

        h->action(h);/*如果此软中断号未决,则执行其处理函数*/

        rcu_bh_qsctr_inc(cpu);

      }

      h++;

      pending >>= 1;

} while (pending);

local_irq_disable();/*开中断*/

pending = local_softirq_pending();/*读入本cpupending*/

if (pending && --max_restart)

     goto restart;/*如果本cpu还有未决的软中断,并且尝试的次数还没有到达最大值,则继续处理*/

if (pending)

    wakeup_softirqd();/*达到了最大次数,还有未决软中断,则唤醒处理软中断的内核线程--ksoftirqd,每个cpu一个*/

从上面的处理可以看出:软中断的执行环境是内核上下文,一次的执行可以对软中断循环执行多遍(期间中断有可能触发新的软中断),另外一个是各cpu完全是独立(taskletaction中,通过每个tasklet链表节点的锁--表示此tasklet的状态,来达到限制同一个tasklet不能在不同的cpu上执行的目的)。由于tasklet和网络部分的关系不是特别大,这里就不细说了。

那么哪些地方会执行do_softirq呢?1是从硬件中断返回时;二是在ksoftirqd中;另外是在一些现实检查软中断的子系统,如网络子系统的代码中。上面已经看到了ksoftirqd内核线程在适当的实际会唤醒,网络子系统中对软中断的处理随后将看到,但是硬件中断返回时对软中断的处理是怎么的呢?我们知道中断处理函数在do_IRQ中被调用,在处理完中断线上的处理函数后,会调用irq_exit,在irq_exit中有这样的语句:

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

       invoke_softirq();/*调用do_softirq或者_do_softirq*/

他检查当前是否是中断上下文,如果不是(),并且有未决的软中断就处理软中断。这几句话看的不是太明白,难道irq_exit还有其他的,不是在中断中的调用点?一查时发现不少调用点,但是不能确定是否都是在中断上下文中的。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值