tasklet中断后半部处理

1.tasklet
2.工作队列
3.软中断
它们都是延后执行的机制!

tasklet:又名“小任务”,任务说的是软中断,tasklet也是基于软中断实现,优先级高于进程,运行在中断上下文中。
linux内核描述tasklet使用的数据结构:
struct tasklet_struct
{
    void (*func)(unsigned long); //底半部处理函数
    unsigned long data;//给底半部处理函数传递的参数,一般传递指针,要注意在处理函数中对数据类型的转换
};

如何使用呢?
1.分配初始化tasklet对象
   方法1:
   DECLARE_TASKLET(tasklet变量名,tasklet处理函数,给处理函数传递的参数);
   方法2:
   struct tasklet_struct tasklet; //分配
   tasklet_init(&tasklet, 处理函数,给处理函数传递的参数); //初始化
2.在顶半部(中断处理函数)中调用tasklet_schedule函数进行登记底半部tasklet,是登记而不是执行!一旦登记成功,顶半部肯定先执行完毕,赶紧释放CPU资源,tasklet的处理函数会在CPU空闲时去执行。

3.注意事项:tasklet还是工作在中断上下文中,遵循中断的处理过程,千万不能做休眠阻塞的事情!

4.tasklet就是将中断处理函数中比较耗时的内容进行了延后执行

案例:将按键中断采用tasklet来实现。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

//定义硬件相关数据结构
struct btn_resource {
    int irq;    //中断号
    char *name; //中断名称
};
//分配初始化按键信息
static struct btn_resource btn_info[] = {
    [0] = {
        .irq = IRQ_EINT(0),
        .name = "KEY_UP"
    },
    [1] = {
        .irq = IRQ_EINT(1),
        .name = "KEY_DOWN"
    }
};

static int mydata = 0x5555;

static void btn_tasklet_func(unsigned long data)
{
    //数据类型转换
    int *p = (int *)data;
    printk("底半部:%s:data = %#x\n", __func__, *p);
}

//1.分配初始化tasklet对象
//第一个参数是tasklet对象名
//第二个参数是tasklet延后处理函数
//第三个参数是给延后处理函数传递的参数
static DECLARE_TASKLET(btn_tasklet, 
                        btn_tasklet_func,
                        (unsigned long)&mydata);

//中断处理函数(顶半部)
static irqreturn_t button_isr(int irq, void *dev_id)
{
    //2.登记底半部tasklet
    tasklet_schedule(&btn_tasklet);
    
    printk("顶半部:%s\n", __func__);
    return IRQ_HANDLED;
}

static int btn_init(void)
{
    int i;

    //申请硬件中断资源和注册中断处理函数
    for (i = 0; i < ARRAY_SIZE(btn_info); i++)
        request_irq(btn_info[i].irq,
                    button_isr,
        IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
                    btn_info[i].name,
                    &btn_info[i]);
    return 0;
}

static void btn_exit(void)
{
    int i;

    //释放硬件中断资源和卸载中断处理函数
    for (i = 0; i < ARRAY_SIZE(btn_info); i++)
        free_irq(btn_info[i].irq,&btn_info[i]);

}
module_init(btn_init);
module_exit(btn_exit);
MODULE_LICENSE("GPL");

猜你喜欢

转载自blog.csdn.net/coolperl/article/details/81272426