工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。 这样,通过工作队列执行的代码能占尽进程上下文的所有优势。
工作队列:可使用内核提供的缺省的共享的默认队列,优点是简单易用,缺点是如果缺省工作队列的负载太多,则执行效率会很低。(工作者线程本质上是一个普通的内核线程,默认情况下,每个CPU均有一个类型为“events”的工作者线程)
也可创建使用自己的工作者线程和工作队列(使用create_workqueue创建)。(ps:使用新建工作线程和默认线程,调用的API部分不同)
Bcmtch15***.c 和ft5306.c触摸驱动均使用的是工作队列实现中断的底半部。
下面以敦泰触摸屏驱动ft5306.c为例,介绍其实现过程:
1、声明工作队列结构体指针:static struct workqueue_struct *synaptics_wq;
2、初始化工作队列:驱动init函数focaltech_ft5306_init中:
synaptics_wq = create_singlethread_workqueue("synaptics_wq");//因为使用的自己创建的工作队列,而非默认的内核的
//create_workqueue和create_singlethread_workqueue都是创建一个工作队列,但是差别在create_singlethread_workqueue可以指定为此工作队列只创建一个内核线程(前一个函数会为每一个处理器分别创建一个内核线程),这样可以节省资源,无需发挥SMP的并行处理优势。
if (!synaptics_wq) {
printk(KERN_ERR "Could not create work queue synaptics_wq: no memory");
return -ENOMEM;}
3、 初始化一个work,并绑定其处理函数:
INIT_WORK(&ts->work, focaltech_ft5306_work_func);
// focaltech_ft5306_work_func为处理函数,ts->work(ts为触摸屏结构体synaptics_rmi4)
//动态地初始化一个由work指向的工作,处理函数为func(无论是动态还是静态创建,默认定时器初始化为0,即不进行延时调度)
//focaltech_ft5306_work_func为使用container_of实现data指针的传递(container_of那就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针)。
struct synaptics_rmi4 *ts = container_of(work, struct synaptics_rmi4, work);
4、使用request_irq申请中断,绑定中断处理函数focaltech_ft5306_irq_handler
focaltech_ft5306_probe 函数中:
if (request_irq(GPIO_TO_IRQ(ts_gpio_irq_pin), focaltech_ft5306_irq_handler,
IRQF_TRIGGER_FALLING, client->name, ts) >= 0) {
printk("Requested IRQ\n");
ts->use_irq = 1;
printk(KERN_INFO "GPIO_%d INT: %d", ts_gpio_irq_pin,
GPIO_TO_IRQ(ts_gpio_irq_pin));
/*if ((ret = set_irq_wake(client->irq, 1)) < 0) {
printk(KERN_ERR "failed to set IRQ wake: %d\n", ret);
}*/
}
5、中断处理函数focaltech_ft5306_irq_handler中,使用queue_work(synaptics_wq, &ts->work);将工作添加到当前处理器对应的链表中
irqreturn_t focaltech_ft5306_irq_handler(int irq, void *dev_id)
{
struct synaptics_rmi4 *ts = dev_id;
queue_work(synaptics_wq, &ts->work);
return IRQ_HANDLED;
}
6、focaltech_ft5306_work_func函数中实现数据的上报等
使用 struct synaptics_rmi4 *ts = container_of(work,struct synaptics_rmi4, work);实现数据的传递
7.驱动exit函数focaltech_ft5306_exit中销毁工作队列:
static void __exit focaltech_ft5306_exit(void)
{
i2c_del_driver(&focaltech_ft5306_driver);
if (synaptics_wq)
destroy_workqueue(synaptics_wq);
}