Linux 將中斷處理例程分爲頂半部和底半部的原因是:爲了解決在中斷處理例程中既要完成
一定數量耗時的任務又要避免使中斷阻塞的時間過長。
- 頂半部是用request_irq註冊的中斷例程,是在中斷上下文中運行的實際響應中斷的例程。
- 底半部是被頂半部調度的並在稍後的某個時間點上運行在非中斷上下文中運行的例程。
典型的情況是:
頂半部保存設備的數據到一個設備特定的緩衝區中並調度它的底半部後退出。
底半部執行其它必要的處理,比如:喚醒進程,啓動另外的I/O等。
例如:當網卡中斷產生時,網卡中斷的頂半部僅接收和保存網絡數據,並在調度它的底半部後退出。
在網卡中斷的底半部中執行網絡數據的協議處理工作。
在Linux中有兩種機制可以用來實現底半部:tasklet 和 workqueue 。
- tasklet 機制速度快,但要求所有的代碼必須是原子的。
- workqueue 機制可以允許高延遲、允許休眠。
tasklet:
- 是由系統在某個時刻調度運行在軟中斷上下文中的特殊函數。
- 可以多次調度,但是多次調度不會累積
- 不同的tasklet可以在SMP上同時運行
- tasklet_schedule是tasklet的調度函數
workqueue:
- 是由系統在某個時刻在工作者進程上下文中調用的一個函數。
- 由於是在進程上下文中運行,故可以休眠
- 不能向用戶空間複製數據,因爲工作者進程不能訪問其它進程的地址空間
- schedule_work是workqueue的調度函數