Softirq和tasklet
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");