1、工作队列描述: 工作队列(work queue)是将任务推后执行的另外一种手段;它的使用方法与Tasklet非常相似,最大的不同就是工作队列的处理函数中可以使用休眠,而Tasklet的处理函数中不允许使用休眠;这是因为Tasklet工作在中断上下文,而工作队列则工作在进程上下文; 工作队列的使用又分为两种情况: (1):利用系统中共享的工作队列来添加自己的工作;这种情况下的处理函数不能消耗太多的时间,否则就会影响共享队列中其它任务的处理; (2):创建自己的工作队列并添加工作; 2、工作、工作队列和工作者线程: 我们把推后执行的任务叫做工作(work),使用数据结构struct work_struct或struct delayed_work来描述;这些工作以队列结构组织成工作队列(workqueue),使用数据结构struct workqueue_struct来描述;而工作者线程就是负责执行工作队列中的工作;系统默认的工作者线程是event/n,自己也可以创建自己的工作者线程; 所以,工作、工作队列、工作者线程,这三者是紧密相关的对象; 其中,struct work_struct描述的工作被调度之后,马上就会被执行;而struct delayed_work描述的工作在被调度之后,需要等待一定时间之后才能被执行; 3、利用系统中共享的工作队列来添加工作: STEP1:声明或编写一个工作处理函数; void xxx_do_work(struct work_struct* work); STEP2:创建一个工作结构体变量,并把工作处理函数和参数的入口地址赋值给这个工作结构体变量; A.编译时静态创建并初始化: DECLARE_WORK(my_work,xxx_do_work,&data); DECLARE_DELAYED_WORK(my_delayed_work,xxx_do_work,&data); B.运行时动态创建并初始化: struct work_struct my_work; INIT_WORK(&my_work,xxx_do_work,&data); struct delayed_work my_delayed_work; INIT_DELAYED_WORK(&my_delayed_work,xxx_do_work,&data); STEP3:把工作结构体变量添加到系统的共享工作队列中,以调度该工作运行; schedule_work(&my_work); schedule_work_on(int cpu, struct work_struct* work); schedule_delayed_work(&my_delayed_work, jiffies); schedule_delayed_work_on(int cpu, struct delayed_work* work, unsigned long jiffies); 执行schedule_work()之后,my_work就会马上被调度,一旦其所在的处理器上的工作者线程被唤醒,它就会被执行;添加到工作队列中的工作完成后,会自动地从工作队列中被删除;带cpu参数的表示在指定CPU上调度运行; 有时候不希望工作马上就被执行,而是希望它经过一段时间的延迟只会再执行;在这种情况下,可以调度它在指定的时间执行;可以调用schedule_delayed_work()函数来调度工作执行; 4、创建自己的工作队列来添加工作: STEP1:声明工作处理函数和一个指向工作队列的指针; void xxx_do_work(struct work_struct* work); struct workqueue_struct* p_queue = NULL; STEP2:创建自己的工作队列和工作结构体变量; p_queue = create_workqueue("name"); //name为工作队列的名称; p_queue = create_rt_workqueue("name"); p_queue = create_freezeable_workqueue("name"); p_queue = create_singlethread_workqueue("name"); struct work_struct my_work; INIT_WORK(&my_work,xxx_do_work,&data); struct delayed_work my_delayed_work; INIT_DELAYED_WORK(&my_delayed_work,xxx_do_work,&data); STEP3:把工作添加到自己创建的工作队列中等待执行(调度工作结构体对象执行); int queue_work(struct workqueue_struct *wq, struct work_struct *work); //queue_work(p_queue,&my_work); int queue_work_on(int cpu, struct workqueue_struct* wq, struct work_struct* work); int queue_delayed_work(struct workqueue_struct* wq, struct delayed_work* work, unsigned long delay); int queue_delayed_work_on(int cpu, struct workqueue_struct* wq, struct delayed_work* work, unsigned long delay); STEP4:如果自己创建的工作队列不再需要时,就要删除; void destroy_workqueue(struct workqueue_struct* wq); 5、其它函数: void flush_workqueue(struct workqueue_struct* wq); 该函数用于等待工作队列中的所有工作都执行完之后才返回;在等待所有待处理的工作执行的时候,该函数会进入休眠状态;所以,它只能用于进程上下文中; int flush_work(struct work_struct* work); void flush_delayed_work(struct delayed_work* work); 这两函数用于等待指定的工作执行完成;返回之前是处于休眠状态的; void flush_scheduled_work(void); 该函数用于刷新已经被调度的工作; int cancel_delayed_work(struct delayed_work* work); 该函数用于取消指定的延迟工作; 例如: 下面的代码用于定义一个工作队列和一个工作队列处理函数: struct work_struct my_wq; //定义工作队列 void my_wq_func(struct work_struct* work); //工作队列处理函数 通过如下代码初始化工作队列my_wq,并把该工作队列my_wq与一个处理函数my_wq_func绑定起来: INIT_WORK(&my_wq, (void (*)(void*))my_wq_func, NULL); 与tasklet_schedule()对应的用于调度工作队列执行的函数为schedule_work();如: schedule_work(&my_wq); //调度工作队列执行 使用工作队列处理中断底半部的设备驱动程序模板如下: //定义工作队列和处理函数: struct work_struct xxx_wq; void xxx_do_work(unsigned long); //中断底半部处理函数: void xxx_do_work(unsigned long) { ...... } //中断顶半部处理函数: irqreturn_t xxx_interrupt(int irq, void* dev_id, struct pt_regs* regs) { //顶半部处理代码 ...... //调度工作队列 schedule_work(&xxx_wq); //剩余处理代码 ...... } //设备驱动模块加载函数 int __init xxx_init(void) { ...... //申请中断 result = request_irq(xxx_irq, xxx_interrupt, SA_INTERRUPT, "xxx", NULL); ...... //初始化工作队列 INIT_WORK(&xxx_wq, (void (*)(void*))xxx_do_work, NULL); ...... } //设备驱动模块卸载函数 void __exit xxx_exit(void) { ...... //释放中断 free_irq(xxx_irq, xxx_interrupt); ...... } 例子: 1、使用系统范围内共享的工作队列的例子: #include <linux/module.h> #include <linux/version.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/delay.h> #include <linux/sched.h> #include <linux/kthread.h> #include <linux/err.h> //工作队列相关 #include <linux/workqueue.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("*************"); MODULE_VERSION("2.6.35.000"); static int flag = 0; //STEP1:实现工作队列处理函数; void my_do_work(struct work_struct* work) { flag = 1; printk("%s:hello, my work queue function\n", __FUNCTION__); }; //STEP2:定义工作结构体对象 static struct work_struct my_work; static int thread_process(void* param) { while(1) { set_current_state(TASK_UNINTERRUPTIBLE); if(kthread_should_stop()) { printk("kernel thread should stop;file:%s;line:%d\n", __FILE__, __LINE__); break; } mdelay(10*HZ); //STEP4:调度工作结构体对象执行:把工作结构体对象添加到系统范围内共享的工作队列中等待执行; if(0 == flag) { schedule_work(&my_work); } else { flag = 0; } } return 123; }; static struct task_struct* my_thread = NULL; static int __init study_init(void) { int err = 0; printk("%s\n", __PRETTY_FUNCTION__); //STEP3:初始化工作结构体对象 INIT_WORK(&my_work, my_do_work); my_thread = kthread_create(thread_process, NULL, "my_thread"); if(IS_ERR(my_thread)) { err = PTR_ERR(my_thread); my_thread = NULL; printk(KERN_ERR "unable to start kernel thread:%d\n", err); return err; } wake_up_process(my_thread); printk("kernel thread start;file:%s;line:%d\n", __FILE__, __LINE__); return 0; } static void __exit study_exit(void) { int ret = -1; printk("%s\n",__PRETTY_FUNCTION__); if(my_thread) { ret = kthread_stop(my_thread); my_thread = NULL; } printk("kernel thread stop,exit code is %d;file:%s;line:%d\n",ret, __FILE__, __LINE__); } module_init(study_init); module_exit(study_exit); 2、使用自己创建的工作队列的例子: #include <linux/module.h> #include <linux/version.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/delay.h> #include <linux/sched.h> #include <linux/kthread.h> #include <linux/err.h> //工作队列相关 #include <linux/workqueue.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("*************"); MODULE_VERSION("2.6.35.000"); static int flag = 0; //STEP1:实现工作队列处理函数; void my_udf_do_work(struct work_struct* work) { flag = 1; printk("%s:hello, my udf work queue function\n", __FUNCTION__); }; //STEP2:定义工作结构体对象; static struct work_struct my_udf_work; //STEP3:定义工作队列指针; static struct workqueue_struct* lp_wq = NULL; static int thread_process(void* param) { while(1) { set_current_state(TASK_UNINTERRUPTIBLE); if(kthread_should_stop()) { printk("kernel thread should stop;file:%s;line:%d\n", __FILE__, __LINE__); break; } mdelay(10*HZ); //STEP6:调度工作结构体对象执行:把工作结构体对象添加到自己创建的工作队列中等待执行; if(0 == flag) { queue_work(lp_wq, &my_udf_work); } else { flag = 0; } } return 123; }; static struct task_struct* my_thread = NULL; static int __init study_init(void) { int err = 0; printk("%s\n", __PRETTY_FUNCTION__); //STEP4:初始化工作结构体对象; INIT_WORK(&my_udf_work, my_udf_do_work); //STEP5:创建自己的工作队列对象(工作者线程对象); lp_wq = NULL; lp_wq = create_workqueue("my_work_queue"); //lp_wq = create_singlethread_workqueue("my_work_queue"); if(!lp_wq) { printk(KERN_ERR "create my work queueu failed\n"); return -1; } my_thread = kthread_create(thread_process, NULL, "my_thread"); if(IS_ERR(my_thread)) { err = PTR_ERR(my_thread); my_thread = NULL; printk(KERN_ERR "unable to start kernel thread:%d\n", err); return err; } wake_up_process(my_thread); printk("kernel thread start;file:%s;line:%d\n", __FILE__, __LINE__); return 0; } static void __exit study_exit(void) { int ret = -1; printk("%s\n",__PRETTY_FUNCTION__); if(my_thread) { ret = kthread_stop(my_thread); my_thread = NULL; } //STEP7:释放自己创建的工作队列; destroy_workqueue(lp_wq); lp_wq = NULL; printk("kernel thread stop,exit code is %d;file:%s;line:%d\n",ret, __FILE__, __LINE__); } module_init(study_init); module_exit(study_exit);
|