軟中斷是 Linux 核心延遲處理高頻事件的關鍵機制(網路封包接收、塊裝置完成、定時器等)。本文基於 Linux 2.6.12 原始碼,剖析 irq_cpustat_t 架構差異、local_softirq_pending() 存取宏、__raise_softirq_irqoff() 觸發邏輯與 do_softirq() 處理流程。
定義於 asm/hardirq.h,架構相關:
typedef struct {
unsigned int __softirq_pending; // 軟中斷待處理位圖
unsigned long idle_timestamp; // 閒置時間戳
unsigned int __nmi_count; // NMI 計數
unsigned int apic_timer_irqs; // APIC 計時器中斷計數
} ____cacheline_aligned irq_cpustat_t;
typedef struct {
unsigned int __softirq_pending;
} ____cacheline_aligned irq_cpustate_t;
____cacheline_align 確保每 CPU 結構獨佔一條快取行,避免虛假共享。全域陣列 irq_stat[NR_CPUS] 儲存各 CPU 狀態。
#ifndef __ARCH_IRQ_STAT
extern irq_cpustat_t irq_stat[];
#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
#endif
#define local_softirq_pending() \
__IRQ_STAT(smp_processor_id(), __softirq_pending)
smp_processor_id() 返回當前 CPU 編號(單核為 0),宏直接讀取對應 CPU 的 __softirq_pending 位圖。
#define __raise_softirq_irqoff(nr) \
do { local_softirq_pending() |= 1UL << (nr); } while (0)
將當前 CPU 的 __softirq_pending 第 nr 位置 1,標記對應軟中斷待處理。nr 對應 enum 定義(HI_SOFTIRQ、TIMER_SOFTIRQ、NET_TX_SOFTIRQ、NET_RX_SOFTIRQ、BLOCK_SOFTIRQ 等)。
在 kernel/softirq.c 中,do_softirq() 輪詢 irq_stat[cpu].__softirq_pending,對每個置位的 bit 呼叫對應 softirq_action 陣列中的處理函式(action->action())。處理過程中:
local_irq_save),防止重入。netif_rx 觸發 NET_RX_SOFTIRQ),循環直到 pending 為零或達 MAX_SOFTIRQ_RESTART(預設 10 次),剩餘交由 ksoftirqd 核心執行緒處理。raise_softirq,耗時工作延遲到軟中斷/執行緒上下文,降低中斷延遲。kernel/softirq.c 通用,架構僅提供 irq_cpustat_t 與 smp_processor_id()。include/linux/interrupt.h、asm/hardirq.h、kernel/softirq.c。軟中斷以 per-CPU 位圖實現高效延遲處理,irq_cpustat_t 封裝架構差異,raise_softirq/do_softirq 構成觸發-處理閉環。理解此機制對網路驅動開發、高效能伺服器調校、核心除錯至關重要。