天天看點

Linux 中斷底半部機制Linux 中斷底半部機制總結

Linux 中斷底半部機制

  • Linux 中斷底半部機制
    • linux中斷底半部
        • 過去的中斷底半部實作機制 bh_base
          • 關于bh_active和 bh_mask
    • 新機制的出現
      • 軟中斷的分析
        • 機制的初始化
  • 總結

linux中斷底半部

因為硬中斷ISR是在關閉中斷的情況下執行的,故而在硬中斷ISR中停留時間過長會影響系統性能。為了能盡可能地縮短硬中斷的時間,linux設定了中斷底半部。也就是說,Linux的中斷分為頂半部(硬中斷)和底半部(軟中斷),軟中斷是在打開中斷響應的情況下執行的。硬中斷中處理那些即時的不可中斷關鍵部分,而底半部處理那些可中斷的非關鍵部分。

過去的中斷底半部實作機制 bh_base[]

bh_base[]為一個32個元素的函數指針數組,并且核心設定了兩個32位無符号整數:bh_active

和bh_mask用于管理這個數組,這兩個無符号整數的每一位對應bh_base中的每一個函數指針。bh_base[]相當于硬中斷當中的irq_desc[]。不過irq_desc[]中的每個元素都代表着一個中斷通道,也就是說每個元素都管理一個中斷服務程式隊列。而bh_base中的每個元素卻最多代表一個bh函數。

關于bh_active和 bh_mask
  • bh_active相當于硬體中斷的“中斷請求寄存器”,而bh_mask相當于“中斷屏蔽寄存器”
  • 需要執行一個bh函數時候就通過一個mark_b将bh_active中的對應位置位。如果bh_mask中的相應位也是1,那麼就允許這個bh函數被執行。每次執行完do_IRQ或者系統調用之後,就會在一個do_bottom_half()函數中執行這個bh函數。

新機制的出現

因為bh_base[]機制實作的底半部具有與硬中斷一樣的”嚴格串行化”的特點,造成了系統效率低下。于是我們需要一個新的底半部實作機制,用于實作非嚴格串行化的底半部。并且為了相容bh_base[]機制(軟體設計開閉原則:對增加開放,對修改關閉),linux的實作政策是這樣的:增加一種底半部架構,然後将bh_base和新的“非串行化機制”納入該架構當中,這個架構就是linux_kernel_2.4當中的“軟中斷(softirq)”.可以這麼描述軟中斷:

  • 軟中斷是一種架構,也是一種機制
  • 這個架構内,有衆多實作底半部的機制,bh機制就是其中一種。
  • bh機制是一種特殊的軟中斷,也可以說是設計嘴保守的,但是最簡單,最安全的軟中斷。
  • 軟中斷一共有四種,定義于include/linux/interrupt.c
enum
 {
     HI_SOFTIRQ=,
     NET_TX_SOFTIRQ,
     NET_RX_SOFTIRQ,
     TASKLET_SOFTIRQ
 };
           

其中NET_TX_SOFTIRQ和NET_RX_SOFTIRQ專門為網絡設計。是以主要的軟中斷機制隻有HI_SOFTIRQ和TASKLET_SOFTIRQ兩種。

軟中斷的分析

系統在初始化的時候調用softirq_init()函數對軟中斷進行初始化。

void __init softirq_init()
 {
     int i;
 
     for (i=; i<; 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);
 }
           

機制的初始化

核心為bh機制設定了一個bh_task_vec[32]數組,這是一個tasklet_struct結構數組。該結構定義如下:

struct tasklet_struct
 {
     struct tasklet_struct *next;
     unsigned long state;
     atomic_t count;
     void (*func)(unsigned long);
     unsigned long data;
 };
           

一個tasklet_struct就代表這一個tasklet,因為bh的實作本身是一個tasklet,隻是在此基礎上增加了更加嚴格的”串行化”限制就成了原來的bh機制。在softirq_init中(285行),對bh的32個tasklet_init調用了tasklet_init之後,它們的函數指針都指向了bh_action。其它軟中斷的初始化都是通過open_softirq()來完成的。

void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
 {
     unsigned long flags;
     int i;
 
     spin_lock_irqsave(&softirq_mask_lock, flags);
     softirq_vec[nr].data = data;
     softirq_vec[nr].action = action;
 
     for (i=; i<NR_CPUS; i++)
         softirq_mask(i) |= (<<nr);
     spin_unlock_irqrestore(&softirq_mask_lock, flags);
 }
           

核心為軟中斷設定了一個以“軟中斷号”為下标的數組softirq_vec[ ],類似與中斷機制中的irq_desc[ ]。這是一個softirq_action結構數組,定義如下:

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

softirq_vec是一個全局變量,是以SMP中的每個CPU看到的都是同一個數組。但是每個CPU各有自己的“軟中斷控制狀态結構”,這些結構形成一個以CPU編号為下标的irq_stat[]。這個數組也是全局變量,每個CPU通過自己的編号來通路。irq_stat定義如下

/* entry.S is sensitive to the offsets of these fields */
 typedef struct 
 {
     unsigned int __softirq_active;
     unsigned int __softirq_mask;
     unsigned int __local_irq_count;
     unsigned int __local_bh_count;
     unsigned int __syscall_count;
     unsigned int __nmi_count;
 /* arch dependent */
 } ____cacheline_aligned irq_cpustat_t;
           

其中softirq_active相當于“軟中斷請求寄存器”,而softirq_mask則相當于“軟中斷屏蔽寄存器”。

函數open_softirq把函數指針填入相應的softirq_vec之外,把每個CPU上的softirq_mask的相應位設定為1,即允許該中斷在每個CPU上運作。

核心還有一個以CPU編号為下标的數組tasklet_hi_vec[],這是一個tasklet_head結構數組,每個tasklet_head結構就是一個tasklet_head結構的隊列頭。

struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned;
           

總結

softirq架構:

在每次do_IRQ結束之後,或者系統調用結束之後,會檢測是否有軟中斷需要處理。如果有的話就調用do_softirq(),而do_softirq()會檢測是哪個softirq(HI_SOFTIRQ?TASKLET_SOFTIRQ?)有中斷請求,然後查詢softirq_vec數組,如果該cpu上的softirq_active對應位置位,就調用softirq_vec中對應位的action。比如說:

cpu上有bh請求需要處理,也就是說softirq_active中的HI_SOFTIRQ位置位了,這時候就會調用softirq_vec[HI_SOFTIRQ].action,也就是softirq_init()函數中安裝的tasklet_hi_action函數,tasklet_hi_action會将該處理器上的tasklet_hi_vec[cpu]隊列中的每一個tasklet。而對于bh來說,每個tasklet都會調用bhaction函數,bhaction函數則根據傳入的nr調用bh_base[]中的函數。

從上面的叙述中可以看到:

  • softirq架構隻有irq_stat[]數組,和softirq_vec數組。irq_stat用于查詢中斷狀态,而softirq_vec則作為軟中斷向量表,儲存這每個軟中斷服務程式入口。
  • 在softirq架構下的tasklet機制。實際上是在softirq_vec這個向量表内安裝了相關的tasklet處理函數(tasklet軟中斷ISR),對每個CPU上的tasklet_hi_vec[cpu]隊列中的每一個tasklet_struct進行處理。也就是說,tasklet機制隻有softirq_vec中的“tasklet軟中斷ISR”、tasklet_hi_vec[cpu]隊列tasklet_struct.(每個tasklet_struct就是一個tasklet執行個體,即一個小任務。)
  • 在softirq架構下的bh機制。bh機制實際上是借助tasklet實作的。它隻是向CPU的tasklet_hi_vec[cpu]送出tasklet_struct,而每個tasklet_struct都負責調用一個bh_base中的函數。

繼續閱讀