# ps x | grep event | grep -v grep 9 ? S 0:00 [events/0] 10 ? S 0:00 [events/1]
struct workqueue_struct { struct cpu_workqueue_struct *cpu_wq; //该数组每一项对应系统中的一个处理器 struct list_head list; const char *name; int singlethread; int freezeable; /* Freeze threads during suspend */ int rt; #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif }
struct cpu_workqueue_struct { spinlock_t lock; //保护该结构 struct list_head worklist; //工作列表 wait_queue_head_t more_work; //等待队列,其中的工作者线程因等待而处于睡眠状态 struct work_struct *current_work; struct workqueue_struct *wq; //关联工作队列结构 struct task_struct *thread; // 关联线程,指向结构中工作者线程的进程描述符指针 } ____cacheline_aligned;
struct work_struct { atomic_long_t data; ...... struct list_head entry;//连接所有链表 work_func_t func; ..... };
static int worker_thread(void *__cwq) { struct cpu_workqueue_struct *cwq = __cwq; DEFINE_WAIT(wait); if (cwq->wq->freezeable) set_freezable(); for (;;) { //线程将自己设置为休眠状态并把自己加入等待队列 prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE); if (!freezing(current) && !kthread_should_stop() && list_empty(&cwq->worklist)) schedule();//如果工作对列是空的,线程调用schedule()函数进入睡眠状态 finish_wait(&cwq->more_work, &wait); try_to_freeze(); //如果链表有对象,线程就将自己设为运行态,脱离等待队列 if (kthread_should_stop()) break; //再次调用run_workqueue()执行推后的工作 run_workqueue(cwq); } return 0; }
static void run_workqueue(struct cpu_workqueue_struct *cwq) { spin_lock_irq(&cwq->lock); while (!list_empty(&cwq->worklist)) { //链表不为空时,选取下一个节点对象 struct work_struct *work = list_entry(cwq->worklist.next, struct work_struct, entry); //获取希望执行的函数func及其参数data work_func_t f = work->func; ...... trace_workqueue_execution(cwq->thread, work); cwq->current_work = work; //把该结点从链表上解下来 list_del_init(cwq->worklist.next); spin_unlock_irq(&cwq->lock); BUG_ON(get_wq_data(work) != cwq); //将待处理标志位pending清0 work_clear_pending(work); lock_map_acquire(&cwq->wq->lockdep_map); lock_map_acquire(&lockdep_map); //执行函数 f(work); lock_map_release(&lockdep_map); lock_map_release(&cwq->wq->lockdep_map); ...... spin_lock_irq(&cwq->lock); cwq->current_work = NULL; } spin_unlock_irq(&cwq->lock); }
int schedule_work(struct work_struct *work) { return queue_work(keventd_wq, work); } int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay) { return queue_delayed_work(keventd_wq, dwork, delay); }
#include <linux/init.h> #include <linux/module.h> #include <linux/workqueue.h> //work_strcut //struct work_struct ws; struct delayed_work dw; void workqueue_func(struct work_struct *ws) //处理函数 { printk(KERN_ALERT"Hello, this is shallnet!\n"); } static int __init kwq_init(void) { printk(KERN_ALERT"===%s===\n", __func__); //INIT_WORK(&ws, workqueue_func); //建需要推后完成的工作 //schedule_work(&ws); //调度工作 INIT_DELAYED_WORK(&dw, workqueue_func); schedule_delayed_work(&dw, 10000); return 0; } static void __exit kwq_exit(void) { printk(KERN_ALERT"===%s===\n", __func__); flush_scheduled_work(); } module_init(kwq_init); module_exit(kwq_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("shallnet"); MODULE_DESCRIPTION("blog.csdn.net/shallnet");上面的操作是使用缺省的工作队列,下面来看一下创建一个新的工作队列是如何操作的?
struct workqueue_struct *create_workqueue(const char *name);name是新内核线程的名字。比如缺省events队列的创建是这样使用的:
struct workqueue_struct *keventd_wq; kevent_wq = create_workqueue("event");
int queue_work(struct workqueue_struct *wq, struct work_struct *work); int queue_delayed_work(struct workqueue_struct *wq,struct delayed_work *work,unsigned long delay);
#include <linux/init.h> #include <linux/module.h> #include <linux/workqueue.h> //work_strcut struct workqueue_struct *sln_wq = NULL; //struct work_struct ws; struct delayed_work dw; void workqueue_func(struct work_struct *ws) { printk(KERN_ALERT"Hello, this is shallnet!\n"); } static int __init kwq_init(void) { printk(KERN_ALERT"===%s===\n", __func__); sln_wq = create_workqueue("sln_wq"); //创建名为sln_wq的工作队列 //INIT_WORK(&ws, workqueue_func); //queue_work(sln_wq, &ws); INIT_DELAYED_WORK(&dw, workqueue_func); // queue_delayed_work(sln_wq, &dw, 10000); // return 0; } static void __exit kwq_exit(void) { printk(KERN_ALERT"===%s===\n", __func__); flush_workqueue(sln_wq); } module_init(kwq_init); module_exit(kwq_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("shallnet"); MODULE_DESCRIPTION("blog.csdn.net/shallnet");
版权声明:本文为博主原创文章,未经博主允许不得转载。
把握linux内核设计(五):下半部机制之工作队列及几种机制的选择
原文地址:http://blog.csdn.net/shallnet/article/details/47115055