linux软中断

                   

 在由内核执行的几个任务之间有些不是紧急的,在必要情况下他们可以延迟一段时间。一个中断处理程序的几个中断服务例程之间是串行执行的,并且通常在一个中断的处理程序结束前,不应该再次出现这个中断。相反,可延迟中断可以在开中断的情况下执行。

linux中所谓的可延迟函数,包括软中断和tasklet以及通过中作队列执行的函数(这个以后说),软中断的分配是静态的(即值编译时定义),而tasklet的分配和初始化可以在运行时进行。

软中断

软中断所使用的数据结构定义

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;

其中softirq_action类型为一个函数指针,从这里也可以看出,软中断的个数是有限的有NR_SOFTIRQS个,具体的定义如下:

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,    

        NR_SOFTIRQS
};

可以看出,一共10个软中断。

struct softirq_action
{
        void       (*action)(struct softirq_action *);
};


软中断的初始化


void open_softirq(int nr, void (*action)(struct softirq_action *))
{
        softirq_vec[nr].action = action;
}

上面函数中,参数nr为softirq_vec[]数组的下标,初始化就是初始化softirq_vec[]数组内容。

初始化了软中断后,要执行,接下来要做的是激活软中断,运用下面函数



void raise_softirq(unsigned int nr)
{
        unsigned long flags;
        
        local_irq_save(flags);
        
        raise_softirq_irqoff(nr);
        local_irq_restore(flags); //恢复中断
}


具体的激活工作由raise_softirq_irqoff函数实现


inline void raise_softirq_irqoff(unsigned int nr)
{       
        
        __raise_softirq_irqoff(nr);

        
        if (!in_interrupt())
                wakeup_softirqd();/*唤醒本地的内核线程*/
}

守护线程softirqd就是对软中断的处理

static int ksoftirqd(void * __bind_cpu)
{
        
        set_current_state(TASK_INTERRUPTIBLE);

        while (!kthread_should_stop()) {
                preempt_disable();

                

                if (!local_softirq_pending()) {
                        preempt_enable_no_resched();
                        schedule();
                        preempt_disable();
                }

                __set_current_state(TASK_RUNNING);

                while (local_softirq_pending()) {

                        
                        if (cpu_is_offline((long)__bind_cpu))
                                goto wait_to_die;
                        do_softirq();
                        preempt_enable_no_resched();
                        cond_resched();
                        preempt_disable();
                        rcu_sched_qs((long)__bind_cpu);
                }
                preempt_enable();
                set_current_state(TASK_INTERRUPTIBLE);
        }
        __set_current_state(TASK_RUNNING);
        return 0;

wait_to_die:
        preempt_enable();
        
        set_current_state(TASK_INTERRUPTIBLE);
        while (!kthread_should_stop()) {
                schedule();
                set_current_state(TASK_INTERRUPTIBLE);
        }
        __set_current_state(TASK_RUNNING);
        return 0;
}


下面是软中断的执行

 
   

asmlinkage void do_softirq(void)
{
        __u32 pending;
        unsigned long flags;

        if (in_interrupt())
                return;

        local_irq_save(flags);

        pending = local_softirq_pending();

        if (pending)
                __do_softirq();

        local_irq_restore(flags);
}
 
  

 

具体由__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));
        lockdep_softirq_enter();

        cpu = smp_processor_id();
restart:
        
        set_softirq_pending(0);

        
        local_irq_enable();

        h = softirq_vec;

        do {
                if (pending & 1) {
                        int prev_count = preempt_count();
                        kstat_incr_softirqs_this_cpu(h - softirq_vec);

                        trace_softirq_entry(h, softirq_vec);
                        h->action(h);
                        trace_softirq_exit(h, softirq_vec);
                        if (unlikely(prev_count != preempt_count())) {
                                printk(KERN_ERR "huh, entered softirq %td %s %p"
                                       "with preempt_count x,"
                                       " exited with x?\n", h - softirq_vec,
                                       softirq_to_name[h - softirq_vec],
                                       h->action, prev_count, preempt_count());
                                preempt_count() = prev_count;
                        }

                        rcu_bh_qs(cpu);
                }
                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();

        account_system_vtime(current);
        _local_bh_enable();
}

到此,linux内核软中断的大致执行和实现基本上分析完了,中间有很多地方没有注释的,主要是考虑到需要别的实现机制以及有的比较易懂。能够自己看懂。

http://www.linuxso.com/linuxrumen/14467.html



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值