传统workqueue
在Linux内核中,工作队列是一种异步处理机制,用于延迟执行一些需要在进程上下文中执行的任务。
工作队列就是底半部机制的其中一种。本质上一种代码推迟执行的机制。
- 代码推迟到工作队列,可以享有进程上下文的所有好处
- 工作队列可以被调度,也可以睡眠
每个cpu上有一个work thread。系统中所有的workqueue会挂入一个全局链表:
static LIST_HEAD(workqueues);
一般而言,当创建一个workqueue的时候会为每一个系统内的processor创建一个内核线程,该线程处理本cpu调度的work。singlethread是workqueue的一个特殊模式。
struct workqueue_struct {
struct cpu_workqueue_struct *cpu_wq; -----per-cpu work queue struct
struct list_head list; ---workqueue list
const char *name;
int singlethread; ----single thread or multi thread
int freezeable; ----和电源管理相关的一个flag
};
struct cpu_workqueue_struct {
spinlock_t lock; ----用来保护worklist资源的访问
struct list_head worklist;
wait_queue_head_t more_work; -----等待队列头
struct work_struct *current_work; ----当前正在处理的work
struct workqueue_struct *wq; ------指向work queue struct
struct task_struct *thread; -------worker thread task
int run_depth; /* Detect run_workqueue() recursion depth */
} ____cacheline_aligned;
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
};
首先,系统中包括若干的workqueue,最著名的workqueue就是系统缺省的的workqueue了:
static struct workqueue_struct *keventd_wq __read_mostly;
如果没有特别的性能需求,那么一般驱动使用keventd_wq就OK了
1、初始化一个work
a)静态定义
#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)
#define DECLARE_DELAYED_WORK(n, f) \
struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)
b)动态定义(先定义一个work_struct结构,然后调用INIT_WORK宏)
#define INIT_WORK(_work, _func) \
do { \
(_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
INIT_LIST_HEAD(&(_work)->entry); \
PREPARE_WORK((_work), (_func)); \
} while (0)
2、调度一个work执行
schedule_work:将work挂入缺省的系统workqueue(keventd_wq)
queue_work:可以将work挂入指定的workqueue
注意:处于pending状态的work不会重复挂入workqueue
3、创建workqueue
#define create_workqueue(name) __create_workqueue((name), 0, 0) //创建普通workqueue,也就是每个cpu创建一个worker thread的那种
#define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1) //创建single thread workqueue && freezeable
#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0) //创建single thread workqueue
4、work执行的时机
work执行的时机是和调度器相关的,当系统调度到worker thread这个内核线程后,该thread就会开始工作。
static int worker_thread(void *__cwq)
导致worker thread进入sleep状态有三个条件(同时满足):
(a)电源管理模块没有请求冻结该worker thread。
(b)该thread没有被其他模块请求停掉。
(c)work list为空,也就是说没有work要处理