參考資訊:
http://jimmychenhaha.blogspot.com/2016/09/softirq.html
https://www.cnblogs.com/wang_yb/archive/2013/04/23/3037268.html
Linux Kernel將中斷處理切成top-half和bottom-half兩部份,top-half指的就是中斷副程式本身,而bottom-half指的就是延遲處理的副程式,如果中斷要處理的事情不需太耗時,就直接在中斷副程式裡處理就可以,如果無法立即完成(如:需要等待或者傳遞大量資料),則可以安排一個延遲處理的副程式,softirq就是一種延遲處理的機制,雖然是延遲處理,不過,softirq也是執行在比較高優先級別的等級,因此,不適合處理太過耗時的事情,但是適用於快速處理的場景,因為,高優先級別的副程式,如果太耗時,將延後Context Switch的發生(單核心來說),導致系統效能出問題,softirq本身是可重複進入的(reentrant),因此,在撰寫softirq程式時,必須要考慮到這個問題,不過有了bottom-half機制,確實可以有效解決中斷阻塞問題
使用步驟:
1. open_softirq() 2. raise_softirq() 3. raise_softirq_irqoff()
由於softirq需要修改Kernel,因此,請先修改檔案(kernel/softirq.c)
const char * const softirq_to_name[NR_SOFTIRQS] = { "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "IRQ_POLL", "TASKLET", "SCHED", "HRTIMER", "RCU", "PocketBeagle" }; EXPORT_SYMBOL(open_softirq); EXPORT_SYMBOL(raise_softirq_irqoff); EXPORT_SYMBOL(raise_softirq);
include/linux/interrupt.h
enum { HI_SOFTIRQ=0, TIMER_SOFTIRQ, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, BLOCK_SOFTIRQ, IRQ_POLL_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the numbering. Sigh! */ RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ POCKETBEAGLE_SOFTIRQ, NR_SOFTIRQS };
P.S. 接著重新編譯Kernel並且更新zImage
main.c
#include <linux/init.h> #include <linux/device.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/gpio.h> #include <linux/interrupt.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Steward Fu"); MODULE_DESCRIPTION("Linux Driver"); #define BUTTON 27 void softirq_handler(struct softirq_action *action) { printk("%s\n", __func__); } static irqreturn_t irq_handler(int irq, void *arg) { raise_softirq(POCKETBEAGLE_SOFTIRQ); return IRQ_HANDLED; } int ldd_init(void) { request_irq(gpio_to_irq(BUTTON), irq_handler, IRQF_TRIGGER_RISING, "gpio_irq", NULL); open_softirq(POCKETBEAGLE_SOFTIRQ, softirq_handler); return 0; } void ldd_exit(void) { raise_softirq_irqoff(POCKETBEAGLE_SOFTIRQ); free_irq(gpio_to_irq(BUTTON), NULL); } module_init(ldd_init); module_exit(ldd_exit);
ldd_init: 設定GPIO中斷以及softirq延遲處理副程式
irq_handler: 安排一個softirq延遲處理
softirq_handler: 列印字串
ldd_exit: 釋放中斷資源以及關閉softirq
完成
# softirq_handler