文章目录
一、workqueue介绍
1、workqueue简介
工作队列属于Linux中断底半部的实现方法之一,它能够将工作延后执行。该机制同时也简化了内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。
2、workqueue特点
- 工作队列有一个对应的延后处理函数,用于执行不紧急、耗时较长的内容。
- 工作队列本身基于进程实现,所以其延后处理函数可以进行休眠操作,所以工作队列诞生的本质就是为了解决tasklet的延后处理函数不能进行休眠的问题,因为有些场合需要在底板部延后的执行内容中进行休眠操作,此时只能选择工作队列。
- 工作队列的优先级最低。
二、workqueue实现
1、workqueue数据结构
1)struct work_struct
该结构体用于描述一项不需要延时的工作任务。
/* @work: 指向驱动定义初始化的工作队列对象本身,通过work指针能够给延后处理函数传递参数 */
typedef void (*work_func_t)(struct work_struct *work);
struct work_struct {
atomic_long_t data;
/* @entry: 双向链表,管理工作队列中待执行的任务。 */
struct list_head entry;
/* @func: 工作队列的延后处理函数,用于处理不紧急且耗时较长的内容,可以进行休眠操作 */
work_func_t func;
};
2)struct delayed_work
该结构体用于描述一项需要延时的工作任务。
struct delayed_work {
struct work_struct work;
struct timer_list timer;
/* target workqueue and CPU ->timer uses to queue ->work */
struct workqueue_struct *wq;
int cpu;
};
3)struct workqueue_attrs
4)struct workqueue_struct
该结构体用于描述一个工作队列。
struct workqueue_struct {
struct list_head pwqs; /* WR: all pwqs of this wq */
struct list_head list; /* PR: list of all workqueues */
struct mutex mutex; /* protects this wq */
int work_color; /* WQ: current work color */
int flush_color; /* WQ: current flush color */
atomic_t nr_pwqs_to_flush; /* flush in progress */
struct wq_flusher *first_flusher; /* WQ: first flusher */
struct list_head flusher_queue; /* WQ: flush waiters */
struct list_head flusher_overflow; /* WQ: flush overflow list */
struct list_head maydays; /* MD: pwqs requesting rescue */
struct worker *rescuer; /* I: rescue worker */
int nr_drainers; /* WQ: drain in progress */
int saved_max_active; /* WQ: saved pwq max_active */
struct workqueue_attrs *unbound_attrs; /* PW: only for unbound wqs */
struct pool_workqueue *dfl_pwq; /* PW: only for unbound wqs */
#ifdef CONFIG_SYSFS
struct wq_device *wq_dev; /* I: for sysfs interface */
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
char name[WQ_NAME_LEN]; /* I: workqueue name */
/*
* Destruction of workqueue_struct is sched-RCU protected to allow
* walking the workqueues list without grabbing wq_pool_mutex.
* This is used to dump all workqueues from sysrq.
*/
struct rcu_head rcu;
/* hot fields used during command issue, aligned to cacheline */
unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */
struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */
struct pool_workqueue __rcu *numa_pwq_tbl[]; /* PWR: unbound pwqs indexed by node */
};
三、workqueue用法
1、API函数
函数 | 功能 |
---|---|
create_workqueue | 创建工作队列。 |
INIT_WORK | 初始化工作队列。 |
INIT_DELAYED_WORK | 初始化延时执行的工作队列。 |
queue_delayed_work | 设置工作队列中某项工作延后执行的时间。 |
cancel_work | 从工作队列中移除某项待执行的工作。 |
cancel_delayed_work | 从延时工作队列中移除某项待执行的工作。 |
flush_workqueue | 清空工作队列中所有待执行的工作。 |
destroy_workqueue | 删除销毁工作队列。 |
… | … |
1)创建工作队列
extern struct workqueue_struct *
__alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
struct lock_class_key *key, const char *lock_name, ...) __printf(1, 6);
#define alloc_workqueue(fmt, flags, max_active, args...) \
__alloc_workqueue_key((fmt), (flags), (max_active), NULL, NULL, ##args)
#define create_workqueue(name) \
alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
#define create_freezable_workqueue(name) \
alloc_workqueue("%s", __WQ_LEGACY | WQ_FREEZABLE | WQ_UNBOUND | \
WQ_MEM_RECLAIM, 1, (name))
#define create_singlethread_workqueue(name) \
alloc_ordered_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, name)
2)初始化工作队列
#define __INIT_WORK(_work, _func, _onstack) \
do { \
/* @__init_work: menuconfig配置了CONFIG_DEBUG_OBJECTS_WORK时有效 */
__init_work((_work), _onstack); \
(_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
INIT_LIST_HEAD(&(_work)->entry); \
(_work)->func = (_func); \
} while (0)
#define INIT_WORK(_work, _func) \
__INIT_WORK((_work), (_func), 0)
#define INIT_DELAYED_WORK(_work, _func) \
__INIT_DELAYED_WORK(_work, _func, 0)
2、编程步骤
- 定义并初始化一个工作队列对象,指定延后处理函数。
- 编写延后处理函数,可以进行休眠操作。
- 在某个地方登记工作队列延后处理函数,如:在顶半部中断处理函数中进行登记,也可以单独登记。
3、举一反三
附录:
1、参考资料
- 以上源码内容参考自:Linux-4.15.18