workqueue

一、workqueue介绍


1、workqueue简介

工作队列属于Linux中断底半部的实现方法之一,它能够将工作延后执行。该机制同时也简化了内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。

2、workqueue特点

  1. 工作队列有一个对应的延后处理函数,用于执行不紧急、耗时较长的内容。
  2. 工作队列本身基于进程实现,所以其延后处理函数可以进行休眠操作,所以工作队列诞生的本质就是为了解决tasklet的延后处理函数不能进行休眠的问题,因为有些场合需要在底板部延后的执行内容中进行休眠操作,此时只能选择工作队列。
  3. 工作队列的优先级最低

二、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、编程步骤

  1. 定义并初始化一个工作队列对象,指定延后处理函数。
  2. 编写延后处理函数,可以进行休眠操作。
  3. 在某个地方登记工作队列延后处理函数,如:在顶半部中断处理函数中进行登记,也可以单独登记。

3、举一反三

参见: /modules/wq_custom

附录:


1、参考资料

  1. 以上源码内容参考自:Linux-4.15.18
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值