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");

 

 
 
 
 
posted @ 2024-04-01 01:35  lethe1203  阅读(14)  评论(0编辑  收藏  举报