Softirq:
核心用softirq_action結構管理軟體中斷的註冊和啟用等操作,它的定義如下:
struct softirq_action { void (*action)(struct softirq_action *); };
只有一個用於回撥的函式指標action。軟體中斷的資源是有限的,核心目前只實現了10種型別的軟中斷,它們是:
enum { HI_SOFTIRQ=0, // 高優先順序軟中斷,通常用於高優先順序任務 TIMER_SOFTIRQ, // 定時器軟中斷,用於處理定時器相關的事件 NET_TX_SOFTIRQ, // 網路傳輸軟中斷,處理網路資料傳送 NET_RX_SOFTIRQ, // 網路接收軟中斷,處理網路資料接收 BLOCK_SOFTIRQ, // 塊裝置軟中斷,處理塊裝置相關的事件 BLOCK_IOPOLL_SOFTIRQ, // 塊裝置 I/O 輪詢軟中斷 TASKLET_SOFTIRQ, // 任務軟中斷,用於處理一些需要延遲執行的任務 SCHED_SOFTIRQ, // 排程軟中斷,用於處理排程器相關的事件 HRTIMER_SOFTIRQ, // 高精度定時器軟中斷,處理高精度定時器事件 RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ // RCU(Read-Copy Update)軟中斷,用於處理 RCU 相關的事件 NR_SOFTIRQS // 軟中斷的數量,用於表示軟中斷陣列的大小 };
如果個人想新增軟中斷,涉及修改中斷處理程式、軟中斷處理程式以及 Softirq 排程器等相關程式碼。所以不建議改動核心目前的10種型別軟中斷
tasklet相關函式:
1、DECLARE_TASKLET:這是一個宏,用於在核心中宣告一個 Tasklet。它的原型如下:
DECLARE_TASKLET(name, func, data); //引數說明 name:Tasklet 的名稱。 func:Tasklet 的處理函式,當 Tasklet 被排程時執行。 data:傳遞給處理函式的引數。
2、tasklet_init:這個函式用於初始化一個 Tasklet 結構體。它的原型如下:
void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); // 引數說明 t:指向要初始化的 Tasklet 結構體的指標。 func:Tasklet 的處理函式。 data:傳遞給處理函式的引數。
3、tasklet_schedule:這個函式用於安排 Tasklet 在適當的時候執行。它的原型如下:
void tasklet_schedule(struct tasklet_struct *t); // 引數說明 t:要安排執行的 Tasklet。
4、tasklet_disable 和 tasklet_enable:這兩個函式用於禁用和啟用 Tasklet。禁用 Tasklet 後,即使呼叫 tasklet_schedule 也不會立即執行 Tasklet。它們的原型如下:
void tasklet_disable(struct tasklet_struct *t); void tasklet_enable(struct tasklet_struct *t); // 引數說明 t:要禁用或啟用的 Tasklet。
5、tasklet_kill:這個函式用於取消安排 Tasklet 的執行。它的原型如下:
void tasklet_kill(struct tasklet_struct *t); // 引數說明 t:要取消的 Tasklet。
tasklet driver demo:
使用tasklet作為中斷下半部的demo如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/interrupt.h> #define IRQ_NUM 42 static int irq_counter = 0; static struct tasklet_struct my_tasklet; // 中斷處理程式的頂半部分 static irqreturn_t my_interrupt_handler(int irq, void *dev_id) { // 執行頂半部分的處理邏輯 irq_counter++; // 排程 Tasklet 處理下半部分 tasklet_schedule(&my_tasklet); return IRQ_HANDLED; } // Tasklet 的下半部分處理程式 static void my_tasklet_handler(unsigned long data) { // 執行下半部分的處理邏輯 pr_info("Tasklet executed. IRQ counter: %d\n", irq_counter); } static int __init my_module_init(void) { int ret; // 初始化 Tasklet tasklet_init(&my_tasklet, my_tasklet_handler, 0); // 註冊中斷處理程式 ret = request_irq(IRQ_NUM, my_interrupt_handler, IRQF_SHARED, "my_interrupt", NULL); if (ret) { pr_err("Failed to register IRQ handler\n"); return ret; } pr_info("My module initialized\n"); return 0; } static void __exit my_module_exit(void) { // 取消註冊中斷處理程式 free_irq(IRQ_NUM, NULL); // 等待 Tasklet 完成並釋放資源 tasklet_kill(&my_tasklet); pr_info("My module exited\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lethe1203"); MODULE_DESCRIPTION("tasklet demo");