Linux中断的实现(三)

        上一篇博客介绍了tasklet实现中断下半部,接下来介绍工作队列实现中断下半部。相对于软中断/tasklet,工作队列运行在进程上下文,允许睡眠。

 

一、工作队列的使用

1、定义并初始化工作队列

创建工作队列函数:

struct workqueue_struct *create_workqueue(const char *name)

函数传参是内核中工作队列的名称,返回值是workqueue_struct结构体的指针,该结构体用来维护一个等待队列。

如:

struct workqueue *heql_wq; //定义工作队列

heql_wq = create_workqueue(“heql”);

 

2、定义并初始化work结构体

内核使用结构体来维护一个加入工作队列的任务:

struct work_struct {                                                                                 

    atomic_long_t data;

    struct list_head entry;

    work_func_t func; //下半部实现的处理函数指针

#ifdef CONFIG_LOCKDEP

    struct lockdep_map lockdep_map;

#endif

};

有静态和动态两种方法:

(1)静态初始化

#define DECLARE_WORK(n, f)                      \                                                    

struct work_struct n = __WORK_INITIALIZER(n, f)

定义并初始化一个叫nwork_struct结构体,它对应的处理函数是f

如:

void my_func(struct work_struct *work)

{

......

}

DECLARE_WORK(mystruct, my_func);

(2)动态初始化

如:

struct work_struct heql_work; //定义work结构体

void heql_func(struct work_struct *work) //处理函数

{

......

}

INT_WORK(&heql_work, heql_func); //初始化work结构体

 

3、调度任务

/*kernel/workqueue.c*/

int queue_work(struct workqueue_struct *wq, struct work_struct *work) 

将指定的任务(work_struct),添加到指定的工作队列中。调度并不代表处理函数能够马上执行,这由内核进程调度决定。

 

4、卸载模块时,刷新并注销等待队列

刷新等待队列:

void flush_workqueue(struct workqueue_struct *wq)

该函数会一直等待,直到指定的等待队列中所有的任务都执行完毕并从等待队列中移除。

注销等待队列:

void destroy_workqueue(struct workqueue_struct *wq)

 

例子:

#include<...>

struct workqueue_struct *heql_wq; //定义工作队列

struct work_struct heql_work; //定义work结构体

void heql_func(struct work_struct *work) //处理函数

{

......

}

irqreturn_t irq_handler(int irq, void *dev_id)

{

......

queue_work(heql_wq, &heql_work); //调度任务

return IRQ_HANDLED;

}

static int __init test_init(void) //模块初始化

{

......

heql_wq = create_workqueue(“heql”); //初始化工作队列

INIT_WORK(&heql_work, heql_func); //初始化work结构体

......

}

static void __exit test_exit(void) //模块卸载

{

flush_workqueue(heql_wq); //刷新工作队列

destroy_workqueue(heql_wq); //注销工作队列

......

}

 

二、使用共享的工作队列

在内核中有一个默认的工作队列events,使用共享的工作队列可以省去创建和注销工作队列的步骤。如果有多个不同的任务都加到这个工作队列中,每个任务调度的速度就会比较慢。一般默认工作队列都能满足需求,不需要创建一个新的工作队列。

 

共享工作队列的使用:

1、实现处理函数,定义并初始化work结构体

这里和之前所说的步骤一样。

 

2、调度任务

默认工作队列中的任务的调度不需要指定工作队列,函数如下:

/*kernel/workqueue.c*/

int schedule_work(struct work_struct *work)

该函数会把work_struct结构体加入到默认工作队列events中。

 

例子:

#include<linux/workqueue.h>

void myfunc(struct work_struct *work)

{

......

}

DECLARE_WORK(mywork, func); //定义并初始化work结构体

static irqreturn_t handler(int irq, void *ptr)

{

......

schedule_work(&mywork);

returnt IRQ_HANDLED;

}

三、总结

以上介绍了工作队列的使用,除此之外,还有函数能够使工作队列的任务延时执行,相关的结构体和函数有:

1struct delayed_work{}

2DECLARE_DELAYED_WORK(n,f)

3INIT_DELAYED_WORK(struct delayed_work *work, void (*function)(void *));

4int queue_delayed_work(struct workqueue_struct *queue, 

struct delayed_work *work, unsigned long delay);

5schedule_delayed_work(struct delayed_work *work, unsigned long delay)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值