假設讓核心定期對裝置進行輪詢。以便處理裝置,那會做非常多無用功,假設能讓裝置在須要核心時主動通知核心,會是乙個聰明的方式,這便是中斷。
在響應乙個特定中斷時,核心會執行乙個函式——中斷處理程式。
中斷處理程式與其它核心函式的差別在於,中斷處理程式是被核心呼叫來響應中斷的,而它們執行於我們稱之為中斷上下文的特殊上下文中。
我們期望讓中斷處理程式執行得快。並想讓它完畢的工作量多,這兩個目標相互制約,怎樣解決——上下半部機制。
我們把中斷處理切為兩半。我們用網絡卡來解釋一下這兩半。
當網絡卡接受到資料報時,通知核心,觸發中斷。所謂的上半部就是,及時讀取資料報到記憶體。防止由於延遲導致丟失,這是非常急迫的工作。讀到記憶體後,對這些資料的處理不再緊迫,此時核心能夠去執行中斷前執行的程式,而對網路資料報的處理則交給下半部處理。
我們先來看一下上半部的處理過程。
中斷處理程式的註冊與登出
裝置驅動程式利用request_irq()註冊中斷處理程式。並啟用給定的中斷線。
int request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long flags,
const char *name,
void *dev)
irq表示中斷號,handler是指向中斷處理程式的指標。request_irq()成功執行返回0,當返回非0值時,表示有發生錯誤,中斷處理程式不會被註冊。
解除安裝裝置驅動程式時,須要登出對應的中斷處理程式,並釋放中斷線。這時須要呼叫free_irq——假設在給定的中斷線上沒有中斷處理程式,則登出響應的處理程式。並
禁用當中斷線。
中斷處理機制
下半部嚴格來說不屬於中斷處理程式(由於中斷返回後再執行下半部),它是中斷處理程式用來縮減自身工作的分擔者。
上下半部劃分原則
(1)假設乙個任務對時間非常敏感。將其放在中斷處理程式中執行;
(2)假設乙個任務和硬體有關,將其放在中斷處理程式中執行;
(3)假設乙個任務要保證不被其它中斷打斷。將其放在中斷處理程式中執行;
(4)其它全部任務。考慮放置在下半部執行。
上下半部的意義
上半部簡單高速。執行時禁止一些或者全部中斷。下半部稍後執行,並且執行期間能夠響應全部的中斷。這樣的設計能夠使系統處於中斷遮蔽狀態的時間盡可能的短,以此來提高系統的響應能力。
下半部實現機制之軟中斷
在中斷處理程式中觸發軟中斷是最常見的形式。在這樣的情況下。中斷處理程式執行硬體裝置的相關操作。然後觸發對應的軟中斷,最後退出。
核心在執行完中斷處理程式後,立即就會呼叫do_softirq()函式,於是軟中斷開始執行中斷處理程式留給它去完畢的剩餘任務。
軟中斷註冊方式例如以下:
open_softirq(net_tx_softirq, net_tx_action);
前面的引數是軟中斷的索引號。後面的是處理函式。軟中斷處理程式執行時。同意響應中斷,但它自己不能休眠。
下半部實現機制之tasklet
tasklet是通過軟中斷實現的,所以它本身也是軟中斷。
首先宣告自己的tasklet,declare_tasklet(name, func, data),當該tasklet被排程後。給定的函式func會被執行。它的引數由data給出。接下來定義tasklet處理程式void tasklet_handler(unsigned long data),然後開始排程。
tasklet由tasklet_schedule()和tasklet_hi_schedule()進行排程。
tasklet_schedule()的執行步驟:
(1)檢查tasklet的狀態是否為tasklet_state_sched。假設是,說明tasklet已經被排程過了,函式立即返回。
(2)呼叫_tasklet_schedule()。
(3)儲存中斷狀態,然後禁止本地中斷。在我們執行tasklet**時,這麼做能夠保證當tasklet_schedule()處理這些tasklet時,處理器上的資料不會弄亂。
(4)把須要排程的tasklet加到每乙個處理器乙個的tasklet_vec鍊錶或tasklet_hi_vec鍊錶的表頭上。
(5)喚醒tasklet_softirq或hi_softirq軟中斷,這樣在下一次呼叫do_softirq()時就會執行該tasklet。
(6)恢復中斷到原狀態並返回。
下半部實現機制之工作佇列(work queue)
假設推後執行的任務須要睡眠。那麼就選擇工作佇列,假設不須要睡眠,那麼就選擇軟中斷或tasklet。
工作佇列能執行在程序上下文,它將工作委託給乙個核心執行緒。我們用結構體workqueue_struct表示工作者執行緒,工作者執行緒是用核心執行緒實現的。而工作者執行緒是怎樣執行被推後的工作——有這樣乙個鍊錶。它由結構體work_struct組成,而這個work_struct則描寫敘述了乙個工作,一旦這個工作被執行完。對應的work_struct物件就從鍊錶上移去,當鍊表上不再有物件時,工作者執行緒就會繼續休眠。這些邏輯是通過函式worker_thread()實現的:
(1)執行緒將自己設定為休眠狀態。並把自己增加到等待佇列中。
(2)假設工作鍊錶是空的。執行緒呼叫schedule()函式進入休眠狀態。
(3)假設鍊錶中有物件,執行緒不會休眠。相反。它會脫離等待佇列。
(4)假設鍊錶非空,呼叫run_workqueue()執行被推後的工作。
另外,cpu_workqueue_struct表示乙個工作者執行緒。而workqueue_struct表示一類工作者執行緒。
建立工作者執行緒,declare_work(name, void (*func) (void *), void *data)或init_work(struct work_struct *work, void (*func) (void *), void *data),前者是靜態建立,後者在執行時通過指標建立。
工作者執行緒建立了,接下來應該定義它要執行的函式work_handler。之後就是用schedule_work(&work)來排程工作執行緒的喚醒與休眠。
Linux核心 之 中斷
中斷處理函式所作的第一件事情是什麼?答案是遮蔽中斷,所以要遮蔽中斷,是因為新的中斷會再次呼叫中斷處理函式,導致原來中斷處理現場的破壞。因為中斷,它是把原來的上下文都存起來,如果是多級中斷的話,它需要存多級的上下文,除非linux能存多級上下文,感覺是能多存的。如果只能存一級,那必然是要遮蔽中斷,不然...
Linux核心開發之中斷處理
一 概念 1 外設的處理速度一般慢於cpu。2 cpu不能一直等待外部事件。所以裝置必須有一種方法來通知cpu它的工作進度,這種方法就是中斷。二 中斷實現 在linux驅動程式中,為裝置實現乙個中斷包含兩個步驟 1 向核心註冊中斷 2 實現中斷處理函式 三 中斷處理子系統 1 根據中斷號找到正確的中...
linux中斷系列之中斷簡介 一
第六章 第一節 中斷簡介 核心主要職責 管理系統中存在的各種裝置,一般以一下兩種方式管理 1 輪詢 核心一定週期訪問裝置,查詢裝置狀態並進行處理,裝置請求不能及時處理,大量消耗cpu資源。2 中斷 裝置在需要時通知核心,核心收到裝置的請求後在做出相應處理,即產生一種電訊號,通過中斷控制器發給cpu,...