工作队列是另外一种下半部执行方式,工作队列在进程上下文执行,工作队列将要推后的工作交给一个内核线程去执行,因为工作队列工作在进程上下文,因此工作队列允许睡眠或重新调度。
因此如果你要推后的工作可以睡眠那么就可以选择工作队列,否则的话就只能选择软中断或 tasklet。
在前面中断的基础上实现:
1.定义结构体变量:
struct work_struct work;
2.在中断初始化之后,初始化 INIT_WORK:
INIT_WORK( 要初始化的工作 , 工作对应的处理函数 );
eg:INIT_WORK(&dev->work, key_work);
3.在中断上半部执行schedule_work:
schedule_work(&dev->work(要调度的工作));
4.调用key_work回调函数,执行中断下半部
static void key_work(struct work_struct *work)
{
//struct imx6uirq_dev *dev = (struct imx6uirq_dev*)data;
struct imx6uirq_dev *dev = container_of(work, struct imx6uirq_dev, work);
dev->timer.data = (unsigned long)dev; //定时器回调函数参数
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(20)); /* 20ms定时 */
}
container_of函数:
container_of的主要作用是:通过已知的一个数据结构成员指针ptr,数据结构类型type,以及这个成员指针在这个数据结构中的成员名member,来获取指向这个数据结构的指针type *。
通过container_of可以获得该成员对应的变量的首地址。
5.参考例子
工作队列使用示例
/* 定义工作(work) */
struct work_struct testwork;
/* work 处理函数 */
void testwork_func_t(struct work_struct *work);
{
/* work 具体处理内容 */
}
/* 中断处理函数 */
irqreturn_t test_handler(int irq, void *dev_id)
{
......
/* 调度 work */
schedule_work(&testwork);
......
}
/* 驱动入口函数 */
static int __init xxxx_init(void)
{
......
/* 初始化 work */
INIT_WORK(&testwork, testwork_func_t);
/* 注册中断处理函数 */
request_irq(xxx_irq, test_handler, 0, "xxx", &xxx_dev);
......
}