linux设备驱动下的工作队列(workqueue)

原创 2012年03月29日 18:50:19

       从表面和使用来看,工作队列类似与tasklet,它们都允许内核代码请求某个函数在将来的时间被调用。

但实际上它们有一些非常重要的区别:

1、  tasklet在软件中断上下文中运行,因此所有的tasklet代码都必须是原子的。而工作队列函数在一个特殊内核进程的上下文总运行,所以具有更好的灵活性。更主要的是工作队列函数可以休眠。

2、  tasklet始终运行在被初始提交的同一处理器上,而工作队列默认是这样。

3、  内核代码可以请求工作队列函数的执行延迟给定的时间间隔。有一种提交工作队列的函数接口是:

int queue_delayed_work(struct workqueue_struct *wq,

                    struct delayed_work *dwork, unsigned long delay)

queue_delayed_work - queue work on a workqueue after delay

 

二者的关键区别在于:tasklet会在很短的时间段内很快执行,并且以原子模式执行,而工作队列函数可具有更长的延迟且不必原子化。

工作队列的初始化:

#define __INIT_WORK(_work, _func, _onstack)				\
	do {								\
		__init_work((_work), _onstack);				\
		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
		INIT_LIST_HEAD(&(_work)->entry);			\
		PREPARE_WORK((_work), (_func));				\
	} while (0)
#endif

#define INIT_WORK(_work, _func)					\
	do {							\
		__INIT_WORK((_work), (_func), 0);		\
	} while (0)


工作队列也是用内核中的list_head双向链表;

 

 

工作队列的提交:

值得注意的是:在一般情况下,我们都会用schedule_work函数来提交工作队列,这里

int schedule_work(struct work_struct *work)
{
return queue_work(keventd_wq, work);
}

该函数是将work_struct加入一个全局的keventd_wq队列中,也就是内核提供的共享的默认工作队列。

如果我们有特殊的延时需求,那我们只有建立自己的专用工作队列。

使用create_workqueue系列宏定义。

然后用下面的函数提交工作队列:

int queue_work(struct workqueue_struct *wq, struct work_struct *work)

int queue_delayed_work(struct workqueue_struct *wq,

                            struct delayed_work *dwork, unsigned long delay)

其中queue_delayed_work就用到了linux的动态定时器,所以才有delay的效果。

我们主要看queue_work函数:

int schedule_work(struct work_struct *work)

{

         return queue_work(keventd_wq, work);

}

 

int queue_work(struct workqueue_struct *wq, struct work_struct *work)

{

         int ret;

 

         ret = queue_work_on(get_cpu(), wq, work);

         put_cpu();

 

         return ret;

}

 

int

queue_work_on(int cpu, struct workqueue_struct *wq, struct work_struct *work)

{

         int ret = 0;

 

         if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {

                   BUG_ON(!list_empty(&work->entry));

                   __queue_work(wq_per_cpu(wq, cpu), work);

                   ret = 1;

         }

         return ret;

}

 

static void __queue_work(struct cpu_workqueue_struct *cwq,

                             struct work_struct *work)

{

         unsigned long flags;

 

         debug_work_activate(work);

         spin_lock_irqsave(&cwq->lock, flags);

         insert_work(cwq, work, &cwq->worklist);

         spin_unlock_irqrestore(&cwq->lock, flags);

}

 

static void insert_work(struct cpu_workqueue_struct *cwq,

                            struct work_struct *work, struct list_head *head)

{

         trace_workqueue_insertion(cwq->thread, work);

 

         set_wq_data(work, cwq);

         /*

          * Ensure that we get the right work->data if we see the

          * result of list_add() below, see try_to_grab_pending().

          */

         smp_wmb();

         list_add_tail(&work->entry, head);

         wake_up(&cwq->more_work);

}


 

最终还是list_add_tail(&work->entry, head); 双向链表随处可见

 

 

工作队列的执行:

tasklet是利用软中断不同,工作队列的执行是在一个特殊的内核进程中运行的。

worker_threadà run_workqueue

worker_thread是怎么来的,暂时不过问了,就当他是一个特殊的内核进程。

 

run_workqueue的内容很明了:遍历链表,执行已提交的工作队列的注册回调函数。

 

从形式上看,workqueuetasklet很类似,在中断顶半部和中断底半部中的使用中,他们的使用方法也是类似的。

 

 

linux工作队列 - workqueue总览

workqueue归入中断子系统是由于和中断处理有密切关系,写博客重要在于整理自己的思绪,写的时候会把一些不懂的细节问题暴露出来,这样会把问题看的更透彻,workqueue的代码在文件kernel/w...
  • l289123557
  • l289123557
  • 2016年10月15日 18:17
  • 3058

Linux workqueue工作原理

1. 什么是workqueue        Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线...
  • MyArrow
  • MyArrow
  • 2012年10月19日 17:02
  • 30678

workqueue机制

workqueue和其他的bottom half最大的不同是它是运行在进程上下文中的,它可以睡眠,这和其他bottom half机制有本质的不同,大大方便了驱动工程师撰写中断处理代码。当然,驱动模块也...
  • qq_31505483
  • qq_31505483
  • 2017年11月14日 20:18
  • 104

tasklet与workqueue的区别及底层实现区别

softirq和tasklet都属于软中断,tasklet是softirq的特殊实现; workqueue是普通的工作队列。 1、softirq 软中断支持SMP,同一个softirq可以在不同...
  • cupidove
  • cupidove
  • 2015年11月19日 14:28
  • 2580

工作队列(workqueue) create_workqueue/schedule_work/queue_work

项目需要,在驱动模块里用内核计时器timer_list实现了一个状态机。 郁闷的是,运行时总报错“Scheduling while atomic”,网上搜了一下: "Scheduling wh...
  • angle_birds
  • angle_birds
  • 2012年12月28日 16:12
  • 16562

workqueue 用法实例

struct my_work_stuct{ int test; struct work_stuct save; }; struct my_work_stuct test_work; ...
  • newtonnl
  • newtonnl
  • 2016年01月20日 16:16
  • 1288

linux 笔记--中断子系统之workqueue

linux workqueue,cmwq
  • yhb1047818384
  • yhb1047818384
  • 2017年03月26日 16:30
  • 303

linux工作队列 - workqueue_struct创建

1.创建workqueue代码分析1.1整体代码分析根据FLAG的不同,创建workqueue的API分好几种(见系列文章1说明),根据情况使用,但最终这些API都会调用到alloc_workqueu...
  • l289123557
  • l289123557
  • 2016年10月16日 19:27
  • 1788

[Linux API]linux 工作队列workqueue

1,功能描述:Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个 数创建线程的数量,使得线程处理的事务能够...
  • Joymine
  • Joymine
  • 2017年07月13日 11:26
  • 491

Linux中Workqueue机制分析

Linux中Workqueue机制分析 软硬件协同设计是未来发展的主流,软硬件的界限越来越模糊,软硬件的设计思想是相通的,实现方法是各异的,实现的结果上当然也存在较大差别,因此,很有必要做好软硬件的...
  • luobin1984
  • luobin1984
  • 2012年11月01日 15:30
  • 2364
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux设备驱动下的工作队列(workqueue)
举报原因:
原因补充:

(最多只允许输入30个字)