3.5.3数据结构的定义

   在具体介绍软中断处理机制之前,我们先介绍一下相关的数据结构,这些数据结构大部分都在/includee/linux/interrupt.h

 1.与软中断相关的数据结构 

 软中断本身是一种机制,同时也是一种基本框架。在这个框架中,既包含了bh机制,也包含了tasklet机制

(1) 内核定义的软中断    

 enum

        {

         HI_SOFTIRQ=0,

         NET_TX_SOFTIRQ,

         NET_RX_SOFTIRQ,

         TASKLET_SOFTIRQ

         };

      内核中用枚举类型定义了四种类型的软中断,其中NET_TX_SOFTIRQNET_RX_SOFTIRQ两个软中断是专为网络操作而设的,而HI_SOFTIRQTASKLET_SOFTIRQ是针对bhtasklet而设的软中断。编码的作者在源码注释中曾提到,一般情况下,不要再分配新的软中断。

  2)软中断向量

      struct softirq_action

{

              void    (*action)(struct softirq_action *);

      void    *data;

        

 

     static struct softirq_action softirq_vec[32] __cacheline_aligned;

从定义可以看出,内核定义了32个软中断向量,每个向量指向一个函数,但实际上,内核目前只定义了上面的四个软中断,而我们后面主要用到的为HI_SOFTIRQTASKLET_SOFTIRQ两个软中断。

 3)软中断控制/状态结构

   softirq_vec[]是个全局量,系统中每个CPU所看到的是同一个数组。但是,每个CPU各有其自己的“软中断控制/状态”结构,这些数据结构形成一个以CPU编号为下标的数组irq_stat[](定义在include/i386/hardirq.h中)

 

typedef struct {

         unsigned int __softirq_pending;

         unsigned int __local_irq_count;

         unsigned int __local_bh_count;

         unsigned int __syscall_count;

         struct task_struct * __ksoftirqd_task; /* waitqueue is too large */

         unsigned int __nmi_count;       /* arch dependent */

} ____cacheline_aligned irq_cpustat_t;

 

irq_cpustat_t irq_stat[NR_CPUS];

 

 irq_stat[]数组也是一个全局量,但是各个CPU可以按其自身的编号访问相应的域。于是,内核定义了如下宏(include/linux/irq_cpustat.h)

#ifdef CONFIG_SMP

#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)

#else

#define __IRQ_STAT(cpu, member) ((void)(cpu), irq_stat[0].member)

#endif 

 

/* arch independent irq_stat fields */

#define softirq_pending(cpu)    __IRQ_STAT((cpu), __softirq_pending)

#define local_irq_count(cpu)    __IRQ_STAT((cpu), __local_irq_count)

#define local_bh_count(cpu)     __IRQ_STAT((cpu), __local_bh_count)

#define syscall_count(cpu)      __IRQ_STAT((cpu), __syscall_count)

#define ksoftirqd_task(cpu)     __IRQ_STAT((cpu), __ksoftirqd_task)

   /* arch dependent irq_stat fields */

#define nmi_count(cpu)          __IRQ_STAT((cpu), __nmi_count)          /* i386, ia64 */

 

2.与tasklet相关的数据结构

  bh函数相比,tasklet是“多序”的bh函数。内核中用tasklet_task来定义一个tasklet

 

 struct tasklet_struct

 {

         struct tasklet_struct *next;

         unsigned long state;

         atomic_t count;

         void (*func)(unsigned long);

         unsigned long data;

};

   从定义可以看出,tasklet_struct是一个链表结构,结构中的函数指针func指向其服务程序。内核中还定义了一个以CPU编号为下标的数组tasklet_vec[]tasklet_hi_vec[]

   struct tasklet_head

{

         struct tasklet_struct *list;

} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));

 

extern struct tasklet_head tasklet_vec[NR_CPUS];

extern struct tasklet_head tasklet_hi_vec[NR_CPUS];

   这两个数组都是tasklet_head结构数组,每个tasklet_head结构就是一个tasklet_struct结构的队列头。

 

3.与bh相关的数据结构

   前面我们提到,bh建立在tasklet之上,更具体地说,对一个bh的描述也是tasklet_struct结构,只不过执行机制有所不同。因为在不同的CPU上可以同时执行不同的tasklet,而任何时刻,即使在多个CPU上,也只能有一个bh函数执行。

(1)   bh的类型

   enum {

         TIMER_BH = 0,  /* 定时器 */

         TQUEUE_BH,     /* 周期性任务队列 */

         DIGI_BH,       /* DigiBoard PC/Xe */

         SERIAL_BH,     /* 串行接口 */

         RISCOM8_BH,       /* RISCom/8 */

         SPECIALIX_BH, /* Specialix IO8+ */

         AURORA_BH,    /* Aurora多端口卡SPARC*/

         ESP_BH,           /* Hayes ESP 串行卡 */

         SCSI_BH,      /* SCSI接口*/

         IMMEDIATE_BH, /* 立即任务队列*/

         CYCLADES_BH,  /* Cyclades Cyclom-Y 串行多端口 */

         CM206_BH,     /* CD-ROM Philips/LMS cm206磁盘 */

         JS_BH,        /* 游戏杆(PC IBM*/

         MACSERIAL_BH, /* Power Macintosh 的串行端口 */

         ISICOM_BH     /* MultiTechISI*/

};

  在给出bh定义的同时,我们也给出了解释。从定义中可以看出,有些bh与硬件设备相关,但这些硬件设备未必装在系统中,或者仅仅是针对IBM PC兼容机之外的某些平台。

2 bh的组织结构

2.4以前的版本中,把所有的bh用一个bh_base[]数组组织在一起,数组的每个元素指向一个bh函数:

 

static void (*bh_base[32])(void);

 

2.4版中保留了上面这种定义形式,但又定义了另外一种形式:

 

    struct tasklet_struct bh_task_vec[32];

 

    这也是一个有32个元素的数组,但数组的每个元素是一个tasklet_struct结构,数组的下标就是上面定义的枚举类型中的序号。