中断的上下半部
以下內容源于朱有鵬《物聯網大講堂》課程的學習,如有侵權,請告知刪除。
因為輸入類設備的輸入都是異步事件,因此一般使用中斷來處理和響應。
1、中斷處理的注意點
- 中斷處理程序處于中斷上下文中,不能和用戶空間數據交互(不能使用copy_to(from)_usr函數);
- 中斷處理程序不能交出CPU(不能休眠、不能schedule);
- ISR運行時間盡可能短,越長則系統響應特性越差。
2、中斷下半部2種解決方案
當中斷處理程序比較長,而又希望優良的響應特性時,linux內核處理中斷的方案是:人為地將處理程序分為兩部分。
(1)為什么要分上半部(top half,又叫頂半部)和下半部(bottom half,又叫底半部)?
- 上半部標記中斷,調度下半部;下半部負責真正的操作(如讀取按鍵鍵值、從網卡讀取緩沖數據等)。
(2)下半部處理策略1:tasklet(小任務)
- 引入tasklet,最主要的是考慮支持SMP,提高SMP多個cpu的利用率;不同的tasklet可以在不同的cpu上運行。但是tasklet屬于中斷上下文,因此不能被阻塞,不能睡眠,不可被打斷。?
(3)下半部處理策略2:workqueue(工作隊列)
- workqueue的突出特點是下半部會交給worker thead,因此下半部處于進程上下文,可以被重新調度,可以阻塞,也可以睡眠。
- workqueue的初始化方式有靜態和動態兩種。?
- 靜態初始化:調用宏DECLARE_WORK,初始化一個中斷的上半部,然后在中斷上半部調用schedule_work()啟動我們的中斷下半部?
- 動態初始化:調用宏 INIT_WORK,初始化一個中斷的上半部,然后在中斷上半部調用queue_work()啟動我們的中斷下半部?
3、tasklet使用實戰
(1)tasklet相關接口介紹
(2)實戰演示tasklet實現下半部
原程序:
static irqreturn_t button_interrupt(int irq, void *dummy) { int flag;s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0)); // input模式flag = gpio_get_value(S5PV210_GPH0(2));s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0f)); // eint2模式input_report_key(button_dev, KEY_LEFT, !flag);input_sync(button_dev);return IRQ_HANDLED; }
使用方案的策略:
4、workqueue實戰演示
(1)workqueue的突出特點
- 下半部會交給worker thead,因此下半部處于進程上下文,可以被調度,因此可以睡眠。
(2)include/linux/workqueue.h
5、中斷上下半部處理原則
(1)必須立即進行緊急處理的極少量任務放入在中斷的頂半部中
- 此時屏蔽了與自己同類型的中斷,由于任務量少,所以可以迅速不受打擾地處理完緊急任務(除非優先級比自己高,被搶占了)。
(2)需要較少時間的中等數量的急迫任務放在tasklet中
- 此時不會屏蔽任何中斷(包括與自己的頂半部同類型的中斷),所以不影響頂半部對緊急事務的處理;
- 同時又不會進行用戶進程調度,從而保證了自己急迫任務得以迅速完成。
(3)需要較多時間且并不急迫(允許被操作系統剝奪運行權)的大量任務放在workqueue中
- 此時操作系統會盡量快速處理完這個任務,但如果任務量太大,期間操作系統也會有機會調度別的用戶進程運行,從而保證不會因為這個任務需要運行時間將其它用戶進程無法進行。
(4)可能引起睡眠的任務放在workqueue中
- 因為在workqueue中睡眠是安全的。在需要獲得大量的內存時、在需要獲取信號量時,在需要執行阻塞式的I/O操作時,用workqueue很合適。
總結
- 上一篇: Unicode 汉字内码表
- 下一篇: Anaconda下载与安装详解