4、下半部
在中斷處理過程中,不能睡眠。另外,它執行的時候,會把當前中斷線在所有處理器上都遮蔽(在ack中完成遮蔽);更糟糕的情況是,如果乙個處理程式是sa_interrupt型別,它執行的時候會禁上所有本地中斷(通過cli指令完成),所以,中斷處理應該盡可能快的完成。所以linux把中斷處理分為上半部和下半部。
上半部由中斷處理程式完成,它通常完成一些和硬體相關的操作,比如對中斷的到達的確認。有時它還會從硬體拷貝資料,這些工作對時間非常敏感,只能靠中斷處理程式自己完成。而把其它工作放到下半部實現。
下半部的執行不需要乙個確切的時間,它會在稍後系統不太繁忙時執行。下半部執行的關鍵在於執行的時候允許響應所有的中斷。最早,linux用」bottom half」實現下半部,這種機制簡稱bh,但是即使屬於不同的處理器,也不允許任何兩個bottom half同時執行,這種機制簡單,但是卻有效能瓶頸。不久,又引入任務佇列(task queue)機制來實現下半部,但該機制仍不夠靈活,沒法代替整個bh介面。
從2.3開始,核心引入軟中斷(softirqs)和tasklet,並完全取代了bh。2.5中,bh最終捨去,在2.6中,核心用有三種機制實現下半部:軟中斷,tasklet和工作佇列。tasklet是基於軟中斷實現的。
軟中斷可以在多個cpu上同時執行,即使它們是同一型別的,所以,軟中斷處理程式必須是可重入的,或者顯示的用自旋鎖保護相應的資料結構。而相同的tasklet不能同時在多個cpu上執行,所以tasklet不必是可重入的;但是,不同型別的tasklet可以在多個cpu上同時執行
。一般來說,tasklet比較常用,它可以處理絕大部分的問題;而軟中斷用得比較少,但是對於時間要求較高的地方,比如網路子系統,常用軟中斷處理下半部工作。
4.1、軟中斷
核心2.6中定義了6種軟中斷:
下標越低,優先順序越高。
4.1.1、資料結構
(1)軟中斷向量
//linux/interrupt.h
struct softirq_action
;//kernel/softirq.c
//軟中斷向量陣列
static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;
核心定義了乙個包含32個軟中斷向量的陣列,所以最多可有32個軟中斷,實際上,核心目前只使用了6個軟中斷。
(2) preempt_count欄位
位於任務描述符的preempt_count是用來跟蹤核心搶占和核心控制路徑巢狀關鍵資料。其各個位的含義如下:
位 描述
0——7 preemption counter,核心搶占計數器(最大值255)
8——15 softirq counter,軟中斷計數器(最大值255)
16——27 hardirq counter,硬體中斷計數器(最大值4096)
28 preempt_active標誌
第乙個計數用來表示核心搶占被關閉的次數,0表示可以搶占。第二個計數器表示推遲函式(下半部)被關閉的次數,0表示推遲函式開啟。第三個計數器表示本地cpu中斷巢狀的層數,irq_enter()增加該值,irq_exit減該值。
巨集in_interrupt()檢查current_thread_info->preempt_count的hardirq和softirq來斷定是否處於中斷上下文。如果這兩個計數器之一為正,則返回非零。
(3) 軟中斷控制/狀態結構
softirq_vec是個全域性量,系統中每個cpu所看到的是同乙個陣列。但是,每個cpu各有其自己的「軟中斷控制/狀態」結構,這些資料結構形成乙個以cpu編號為下標的陣列irq_stat(定義在include/asm-i386/hardirq.h中)
typedef struct ____cacheline_aligned irq_cpustat_t;
//位於kernel/softirq.c
irq_cpustat_t irq_stat[nr_cpus] ____cacheline_aligned;
4.1.2、軟中斷初始化
可以通過open_softirq註冊軟中斷處理程式:
//位於kernel/softirq.c
//nr:軟中斷的索引號
// softirq_action:處理函式
//data:傳遞給處理函式的引數值
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
void __init softirq_init(void)
軟中斷執行時,允許響應中斷,但它自己不能睡眠,
4.1.3、觸發軟中斷
raise_softirq會將軟中斷設定為掛起狀態,並在下一次執行do_softirq中投入執行。
//位於kernel/softirq.c
void fastcall raise_softirq(unsigned int nr)
inline fastcall void raise_softirq_irqoff(unsigned int nr)
該函式觸發軟中斷前,先要關閉中斷,之後再恢復;如果之前中斷已經關閉,可以直接呼叫raise_softirq_irqoff()觸發軟中斷。
在中斷服務例程中觸發軟中斷是最常見的形式。而中斷服務例程通常作為裝置驅動的一部分。例如,對於網路裝置,當介面收到資料時,會產生乙個中斷,在中斷服務例程中,最終會呼叫netif_rx函式處理接到的資料,而netif_rx作相應處理,最終以觸發乙個軟中斷結束處理。之後,核心在執行中斷處理任務後,會呼叫do_softirq()。於是軟中斷就通過軟中斷處理函式去處理留給它的任務。
4.1.4、軟中斷執行
(1) do_softirq()函式
//處理軟中斷,位於arch/i386/kernel/irq.c
asmlinkage void do_softirq(void)
h++;
pending >>= 1;
} while (pending);
//關閉中斷
local_irq_disable();
//再一次檢查軟中斷位圖,因為在執行軟中斷處理函式時,新的軟中斷可能產生.
pending = local_softirq_pending();
if (pending && --max_restart)
goto restart;
/*如果還有多的軟中斷沒有處理,通過wakeup_softirqd喚醒核心執行緒處理本地cpu餘下的軟中斷.
*/if (pending)
wakeup_softirqd();
//減softirq counter的值
__local_bh_enable();
}
(3)軟中斷執行點
核心會週期性的檢查是否有掛起的軟中斷,它們位於核心**的以下幾個點:
(1)核心呼叫local_bh_enable()函式開啟本地cpu的軟中斷:
//位於kernel/softirq.c
void local_bh_enable(void)
(2)do_irq函式完成i/o中斷處理,呼叫irq_exit()時。
(3)核心執行緒ksoftirqd被喚醒。
(4) smp_apic_timer_interrupt()完成處理本地時鐘中斷。
理解Linux中斷 (3)
4 下半部 在中斷處理過程中,不能睡眠。另外,它執行的時候,會把當前中斷線在所有處理器上都遮蔽 在ack中完成遮蔽 更糟糕的情況是,如果乙個處理程式是sa interrupt型別,它執行的時候會禁上所有本地中斷 通過cli指令完成 所以,中斷處理應該盡可能快的完成。所以linux把中斷處理分為上半部...
linux 中斷理解
1 程序 執行緒只針對的是應用層,而核心呼叫 驅動沒有這種概念,呼叫的都是核心呼叫裡相同的函式或變數,所以應用層多個應用操作同個硬體時,特別是要加互斥操作,8250通過cs針腳決定傳送資料給哪個串列埠 2 傳送 接收的解決併發操作,主要防止重複呼叫該函式,等待函式的硬體還沒操作完才允許再呼叫,接收一...
彙編 深度理解中斷
要求 利用t0的工作模式1產生1ms定時,在p1.0引腳輸出週期為2ms的方波。設微控制器晶振頻率fosc 12mhz。要求如下 分別採用查詢方式和中斷方式編寫程式。一 中斷模式 cpl p1.0 控制翻轉 設定初值。中斷 org 0000h 偽指令 ljmp main 這是實際上的第一條指令,使用...