# 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