古老的BH、tasklet、softirq

  1. 古老的BH:作为一种特殊的tasklet

    kernel/softirq.c : static void (*bh_base[32])(void);

                                            struct tasklet_struct bh_task_vec[32];

在softirq_init中,注册32个bh_task_vec的函数指针为 bh_action; 
TASKLET_SOFTIRQ : tasklet_action;
HI_SOFTIRQ :              tasklet_hi_action;
NET_RX_SOFTIRQ :   net_rx_action;  [net_dev_init]
NET_TX_SOFTIRQ:    net_tx_action;

在sched_init中注册 TIMER_BH的处理函数指针为 timer_bh;
 init_bh(TIMER_BH, timer_bh);


对于数据包的接收发送,标志对应的 NET_RX_SOFTIRQ / NET_TX_SOFTIRQ;
对于应用的 tasklet ,标志对应的 TASKLET_SOFTIRQ;
对于古老的BH,例如时钟中断,在do_IRQ -> timer_interrupt -> do_timer_interrupt -> do_timer : 
  mark_bh(TIMER_BH) -> tasklet_hi_schedule(bh_task_vec+TIMER_BH)
  即将 TIMER_BH 所对应的 bh_task_vec 结构体挂接到对应的CPU的 tasklet_hi_vec 链表中,并标志HI_SOFTIRQ。
  do_softirq时,tasklet_hi_action 遍历对应CPU上的 tasklet_hi_vec 链表中的 tasklet_struct,执行其相应的action,也就是 bh_action 函数。
  bh_action 函数是个包装体,用于实际调用 bh_base 数组中的函数。对于时钟中断也就是 sched_init 中注册的 timer_bh 函数。
  




 

void __init softirq_init()
{
    
int i;

    
for (i=0; i<32; i++)
        tasklet_init(bh_task_vec
+i, bh_action, i);

    open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
    open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
}

 

void tasklet_init(struct tasklet_struct *t,
          
void (*func)(unsigned long), unsigned long data)
{
    t
->next = NULL;
    t
->state = 0;
    atomic_set(
&t->count, 0);
    t
->func = func;
    t
->data = data;
}


 

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

 

void fastcall __tasklet_hi_schedule(struct tasklet_struct *t)
{
    
int cpu = smp_processor_id();
    unsigned 
long flags;

    local_irq_save(flags);
    t
->next = tasklet_hi_vec[cpu].list;
    tasklet_hi_vec[cpu].list 
= t;
    cpu_raise_softirq(cpu, HI_SOFTIRQ);
    local_irq_restore(flags);
}

 

 

static void tasklet_hi_action(struct softirq_action *a)
{
    
int cpu = smp_processor_id();
    
struct tasklet_struct *list;

    local_irq_disable();
    list 
= tasklet_hi_vec[cpu].list;
    tasklet_hi_vec[cpu].list 
= NULL;
    local_irq_enable();

    
while (list) {
        
struct tasklet_struct *= list;

        list 
= list->next;

        
if (tasklet_trylock(t)) {
            
if (!atomic_read(&t->count)) {
                
if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
                    BUG();
                t
->func(t->data);
                tasklet_unlock(t);
                
continue;
            }
            tasklet_unlock(t);
        }

        local_irq_disable();
        t
->next = tasklet_hi_vec[cpu].list;
        tasklet_hi_vec[cpu].list 
= t;
        __cpu_raise_softirq(cpu, HI_SOFTIRQ);
        local_irq_enable();
    }
}


static void bh_action(unsigned long nr)
{
    
int cpu = smp_processor_id();

    
if (!spin_trylock(&global_bh_lock))
        
goto resched;

    
if (!hardirq_trylock(cpu))
        
goto resched_unlock;

    
if (bh_base[nr])
        bh_base[nr]();

    hardirq_endlock(cpu);
    spin_unlock(
&global_bh_lock);
    
return;

resched_unlock:
    spin_unlock(
&global_bh_lock);
resched:
    mark_bh(nr);
}