Linux内核深度解析之中断、异常和系统调用——中断下半部之工作队列

本文详细解析了Linux工作队列(workqueue)的原理与编程接口,介绍如何使用内核线程异步执行函数,包括工作项、延迟工作项、全局与专用工作队列的管理,以及工人处理工作和工人池动态管理机制。

工作队列

工作队列(work queue)是使用内核线程异步执行函数的通用机制。

工作队列是中断处理程序的一种下半部机制,中断处理程序可以把耗时比较长并且可能睡眠的函数交给工作队列。

工作队列不完全是中断处理程序的下半部,同时内核的其他模块也可以将异步执行的函数交给它执行。

1. 编程接口

内核使用工作项保存需要异步执行的函数,工作项的数据接口是work_struct,其定义如下:

include/linux/workqueue.h
struct work_struct {
	atomic_long_t data;
	struct list_head entry;
	work_func_t func;		/* 异步执行的函数 */
};

typedef void (*work_func_t)(struct work_struct *work);		/* 异步执行的函数原型 */

有一类工作项称为延迟工作项,其数据类型为delayed_work,定义如下:

include/linux/workqueue.h
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;
};

把延迟工作项添加到工作队列中的时候,延迟一段时间才会真正地把工作项添加到工作队列中。

工作队列分为两种,一种是内核定义的,一种是自己创建的。内核定义的工作队列如下:

include/linux/workqueue.h
extern struct workqueue_struct *system_wq;		/* 如果工作项的执行时间比较短,应该使用这个工作队列 */
extern struct workqueue_struct *system_highpri_wq;		/* 高优先级的工作队列 */
extern struct workqueue_struct *system_long_wq;		/* 如果工作队列的执行时间比较长,应该使用这个工作队列 */
extern struct workqueue_struct *system_unbound_wq;		/* 这个工作队列使用的内核线程不绑定到某个特定的处理器 */
extern struct workqueue_struct *system_freezable_wq;		/* 这个工作队列可以冻结 */
extern struct workqueue_struct *system_power_efficient_wq;		/* 如果开启了工作队列模块的参数“wq_power_efficient”,那么这个工作队列倾向于省电,否则根system_wq相同 */
extern struct workqueue_struct *system_freezable_power_efficient_wq;		/* 这个工作队列和system_power_efficient_wq的区别是可以冻结 */

(1)定义工作项

定义一个静态的工组项:

DECLARE_WORK(n, f)        /* 参数n是变量名称,参数f是工作项的处理函数 */

定义一个静态的延迟工作项:

DECLARE_DELAYED_WORK(n, f)        /* 参数n是变量名称,参数f是工作项的处理函数 */

定义一个静态的延迟工作项,但使用可推迟的定时器(deferrable timer):

DECLARE_DEFERRABLE_WORK(n, f)        /* 参数n是变量名称,参数f是工作项的处理函数 */

动态初始化一个工作项:

INIT_WORK(_work, _func)        /* 参数_work是工作项地址,参数_func是需要异步执行的函数 */

动态初始化一个工作项,工作项是栈里面的局部变量:

INIT_WORK_ONSTACK(_work, _func)        /* 参数_work是工作项地址,参数_func是需要异步执行的函数 */

动态初始化一个延迟工作项:

INIT_DELAYED_WORK(_work, _func)

动态初始化一个延迟工作项,工作项是栈里面的局部变量:

INIT_DELAYED_WORK_ONSTACK(_work, _func)

动态初始化一个延迟工作项,但使用可推迟的定时器:

INIT_DEFERRABLE_WORK(_work, _func)

动态初始化一个延迟工作项,工作项是栈里面的局部变量,但使用可推迟的定时器:

INIT_DEFERRABLE_WORK_ONSTACK(_work, _func)

(2)全局工作队列

在全局工作队列中添加一个工作项:

bool schedule_work(struct work_struct *work);

在全局工作队列中添加一个工作项,并且指定工作项的处理器:

bool schedule_work_on(int cpu, struct work_struct *work);

在全局工作队列中添加一个延迟工作项:

bool schedule_delayed_work(struct delayed_work *dwork,
					 unsigned long delay)		/* 参数delay是把工作项添加到工作队列中之前等待的时间,单位是嘀嗒(tick) */

在全局工作队列中添加一个延迟工作项,并且指定工作项的处理器:

bool schedule_delayed_work_on(int cpu, struct delayed_work *dwork,
					    unsigned long delay)		/* 参数delay是把工作项添加到工作队列中之前等待的时间,单位是嘀嗒(tick) */

冲刷全局工作队列,确保全局工作队列中的所有工作项执行完:

bool flush_work(struct work_struct *work);

(3)专用工作队列

分配工作队列:

/* 参数fmt是工作队列名称的格式 */
/* 参数flag是标志位,可以是0,也可以是下面这些标志位的组合 */
enum {
	WQ_UNBOUND		= 1 << 1, 		/* 处理工作项的内核线程不绑定到任何特定的处理器 */
	WQ_FREEZABLE		= 1 << 2, 		/* 在系统挂起的时候冻结 */
	WQ_MEM_RECLAIM		= 1 << 3, 		/* 在内存回收的时候可能使用这个工作队列 */
	WQ_HIGHPRI		= 1 << 4, 		/* 高优先级 */
	WQ_CPU_INTENSIVE	= 1 << 5, 		/* 处理器密集型 */
	WQ_SYSFS		= 1 << 6, 
	WQ_POWER_EFFICIENT	= 1 << 7,		/* 省电 */
	__WQ_DRAINING		= 1 << 16, 
	__WQ_ORDERED		= 1 << 17, 
	__WQ_LEGACY		= 1 << 18, 
	__WQ_ORDERED_EXPLICIT	= 1 << 19, 
	WQ_MAX_ACTIVE		= 512,	  
	WQ_MAX_UNBOUND_PER_CPU	= 4,	 
	WQ_DFL_ACTIVE		= WQ_MAX_ACTIVE / 2,
};
/* 参数max_active是每个处理器可以同时执行的工作项的最大数量,0表示使用默认值 */
/* 参数args是传给参数fmt的参数 */
alloc_workqueue(fmt, flags, max_active, args...)

分配一个有序的工作队列,有序的工作队列在任何时刻,按照入队的顺序只执行一个工作项:

alloc_ordered_workqueue(fmt, flags, args...)

在指定的工作队列中添加一个工作项:

bool queue_work(struct workqueue_struct *wq, struct work_struct *work);

在指定的工作队列中添加一个工作项,并且指定执行工作项的处理器:

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

冲刷工作队列,确保工作队列中的所有工作项执行完:<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值