Linux 软中断实现

1. 软中断初始化

Linux目前支持10种sofirq,且不支持驱动开发者添加softirq(可以用tasklet)

10种类型如下:

enum
{
    HI_SOFTIRQ=0,//最高优先级
    TIMER_SOFTIRQ,//timer
    NET_TX_SOFTIRQ,//网络收发数据
    NET_RX_SOFTIRQ,
    BLOCK_SOFTIRQ,//块设备
    BLOCK_IOPOLL_SOFTIRQ,
    TASKLET_SOFTIRQ,//tasklet专有软中断
    SCHED_SOFTIRQ,//调度软中断
    HRTIMER_SOFTIRQ, //Hrtimer软中断/* Unused, but kept as tools rely on the
                numbering. Sigh! */
    RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */

    NR_SOFTIRQS
};

系统初始化时,为每个cpu起一个RT进程处理softirq

smpboot_register_percpu_thread(&softirq_threads),处理函数为run_ksoftirqd

软中断按照优先级执行,软中断号越小,优先级越高。一个软中断,可以在不同cpu上运行,所以内核给每个cpu定义了软中断标记irq_stat,内核其他模块,可以通过open_softirq函数把软中断处理函数安装到softirq_vec数组。

2. 软中断的执行

内核模块可以调用raise_softirq(int nr)挂起一个软中断,

而系统在处理完硬件中断后调用irq_exit(),接着就会处理软中断

void irq_exit(void)
{

/*只有不在硬中断,软中断,或在软中断没有disable时,且本地cpu有软中断才会执行软中断 */

    if (!in_interrupt() && local_softirq_pending())
        invoke_softirq();//处理软中断
}

__do_softirq重点代码分析

asmlinkage __visible void  __do_softirq(void)
{

    __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);//进来先disable软中断,防止在irq_exit()进来两次

restart:

    local_irq_enable();//打开中断,本地cpu可以响应硬件中断,也就是softriq在开中断状态执行

    while ((softirq_bit = ffs(pending))) {//循环遍历pending,依次执行softirq
        unsigned int vec_nr;
        int prev_count;

        h += softirq_bit - 1;
        vec_nr = h - softirq_vec;
        prev_count = preempt_count();
        h->action(h);//执行softirq处理函数
        h++;
        pending >>= softirq_bit;
    }

    local_irq_disable();/* 关中断,再次判断本地cpu是否有softirq被挂起*/

    pending = local_softirq_pending();
    deferred = softirq_deferred_for_rt(pending);//如果本地cpu有RT进程,减少softirq执行

/*

这里有三个条件:

1. 一次__do_softirq执行不超过2ms,

2. 没有进行需要调度

3. restart执行不超过10次

*/

    if (pending) {
        if (time_before(jiffies, end) && !need_resched() &&
            --max_restart)//irq_exit
            goto restart;
    }

/* 如果还有softirq需要执行,然后唤醒softirqd线程,继续处理软中断*/
    if (pending | deferred)
        wakeup_softirqd();
 /*最后使能软中断 */
    __local_bh_enable(SOFTIRQ_OFFSET);
    
}

3. tasklet实现

tasklet是特殊的sotfirq,处理函数如下

static void tasklet_action(struct softirq_action *a)
{
    while (list) {
        struct tasklet_struct *t = list;
        list = list->next;
        if (tasklet_trylock(t)) {//这里保证一个tasklet,同一时间,只能在一个cpu运行
            if (!atomic_read(&t->count)) {//判断tasklet是否被disable
                if (!test_and_clear_bit(TASKLET_STATE_SCHED,
                            &t->state))
   
                t->func(t->data);//执行tasklet处理函数
                tasklet_unlock(t);
                continue;
            }
            tasklet_unlock(t);
        }
    }
}

tasklet操作函数

tasklet_init
tasklet_kill/tasklet_kill_immediate
tasklet_schedule
tasklet_enable
tasklet_disable

4. softirq相关总结

1. 同一个softirq可以在不同的CPU上同时运行,softirq必须是可重入的

2. 软中断是在编译期间静态分配的,它不像tasklet那样能被动态的注册或去除

3. tasklet是基于softirq实现,同一个tasklet只能同时在一个cpu上执行,tasklet无需关心互斥问题.

4. 不同的tasklet可以在不同cpu上运行,提高了SMP效率

5. workqueue工作在线程环境,可以休眠.

6.softirq执行点有两个:irq_exit()和在进程调用raise_softirq()后,唤醒softirqd线程处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值