Linux内核学习之中断(2)-工作队列

工作队列

[概述]

工作队列是一种将工作推后执行的的形式,工作队列可以把工作推后,交由一个内核线程去执行,占有进程上下文的所有优势,允许重新调度和睡眠。

 

[工作队列的实现]

工作队列子系统是一个用于创建内核线程的接口,通过它创建的进程负责执行由内核其他部分排到队列里的任务。它创建的这些内核线程称作工作者线程(worker thread)。工作队列子系统提供了一个缺省的工作者线程来处理推后的工作,所以我们大多数情况下,没必要自己去创建工作者线程,使用默认的就OK。

Linux kernel development 3 上对工作队列的实现原理讲的很清楚了,这里就不再详述。具体来看一个实例

 

[实例]

static struct input_dev *button_dev;
static struct work_struct button_wq;

在做实际的驱动开发的时候,不推荐使用全局变量,因为全局变量是造成竞争条件的主要原因。

 

[中断处理程序]

static irqreturn_t button_interrupt(intirq, void *p)
{
         schedule_work(&button_wq);
         returnIRQ_RETVAL(IRQ_HANDLED);
}

schedule_work(&work)函数用来调度work,把work提交给缺省的events工作者线程(插入工作任务链表中)。work马上会被调度,一旦其所在的处理器上的工作者线程被唤醒,唤醒的工作者队列会遍历整个工作任务链表,如果有工作,它就会被执行,否则继续睡眠。

Schedule_work_delay(&work, delay) 和schedule_work函数的作用相同,唯一区别就是延迟delay时间后才会执行。

 

[工作队列处理函数]

void work_handler(struct work_struct *data)
{
         /*get pin value <down 0, up 1> */
         intval = s3c2410_gpio_getpin(S3C2410_GPG(0));
 
         input_report_key(button_dev,KEY_1, val);
         input_sync(button_dev);
}

完成按键信息的获取和上报工作。

 

[模块初始化函数]

static int __init button_init(void)
{
         interr;
 
         if(request_irq(BUTTON_IRQ, button_interrupt, 
                                               IRQ_TYPE_EDGE_BOTH,DEV_NAME, NULL)) {
                   printk(KERN_ERR"cannotallocate irq");
                   return- EBUSY;
         }
        
         ……
 
         INIT_WORK(&button_wq,work_handler);
 
         printk("initialized\n");
         return0;
}

初始化函数主要完成了两个工作:

1、  申请中断

2、  创建一个推后的工作button_wq,有两种方法:

动态创建:

INIT_WORK(struct work_struct work, void (*func)(void *)), 在新内核里,INIT_WORK已经发生了变化,少了第三个参数。可以参考http://hi.baidu.com/amokefei/blog/item/db998b2e1885a134d52af13e.html

 

静态创建:

DECLARE_WORK(name,func) 创建一个名为name,处理函数为func的work_struct结构体。

不管是动态还是静态,都是填充work struct 结构体。

 

有兴趣可以去看内核里gpio_keys.c的实现代码,一个典型的work queue的实现例子。

你可能感兴趣的:(工作,struct,input,button,delay,linux内核)