古老的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);
}