linux内核源码分析中断work_queue
Posted 为了维护世界和平_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux内核源码分析中断work_queue相关的知识,希望对你有一定的参考价值。
目录
一、工作队列
工作队列可以把工作推后,交由一个内核线程去执行,工作队列允许重新调度甚至是睡眠。
内核把推迟的任务交给特定的通用线程的这样一种接口
用途:中断处理、进程同步、定时等场合。可以使用等待队列实现阻塞进程的唤醒。它以队列为基础数据结构,与进程调度机制紧密结合,能够用于实现内核中的异步时间通知机制,同步对系统资源的访问等待
二、工作队列结构体
1、正常工作结构体
struct work_struct
atomic_long_t data;
struct list_head entry;
work_func_t func;
...
;
2、延迟工作结构体
queue_delayed_work用于向工作队列提交delayed_work实例,它确保在延期工作执行之前,少会经过由delay指定的一段时间。
struct delayed_work
struct work_struct work;
struct timer_list timer; //定时器,用于实现延迟
;
3、工作队列
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 list_head maydays; /* MD: pwqs requesting rescue */
struct worker *rescuer; /* MD: 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 */
char name[WQ_NAME_LEN]; /* I: workqueue name */
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 */
;
三、工作队列初始化(系统自带)
缺省的工作者线程都会从多个地方得到后被推后的工作,交给缺省的工作线程去做。
系统默认的工作队列名:keventd_wq
默认的工作者线程:events/n,n代表处理器编号
例如:单处理器的系统只有events/0这样一个线程,而双处理器的系统就会多一个events/1线程。
缺省系统调用为
start_kernel->rest_init->do_basic_setup->init_workqueues
工作队列相关函数
//静态创建
DECLARE_WORK(name,fun)
//带延时,
DECLARE_DELAYED_WORK(name,fun)
//动态创建
INIT_WORK(_work, _func)
//带延时
INIT_DELAYED_WORK(_work, _func)
工作调度
int schedule_work(struct work_struct *work)
//延迟调度
int schedule_delayed_work(struct delay_work *dwork, unsigned long delay)
刷新与取消
//刷新工作队列
void flush_scheduled_work(void)
//取消延迟工作
static inline int cancel_delayed_work(struct delayed_work *work)
缺省工作队列示例
每隔一秒进行一次调度,并将新的值传递到后执行队列中
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/socket.h>
#include <net/sock.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#define BUF_SIZE 1024
struct task_struct *main_task;
struct my_work
struct work_struct w;
int data;
;
static struct my_work real_work;
static inline void sleep(unsigned sec)
__set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(sec * HZ);
static void my_work_func(struct work_struct *work)
struct my_work *pwork;
pwork = container_of(work, struct my_work, w);
printk(KERN_NOTICE "index %d\\n", pwork->data);
static int queue_work_(void *data)
int index = 0;
INIT_WORK(&real_work.w, my_work_func);
while (!kthread_should_stop())
printk(KERN_NOTICE "server run %d\\n", index);
real_work.data = index;
if (schedule_work(&real_work.w) == 0)
printk(KERN_NOTICE " work failed!\\n");
index ++;
sleep(1);
return 0;
static int model_init(void)
printk("init, workqueue \\n");
//task_struct init
main_task = kthread_run(queue_work_,NULL,"queue_work");
return 0;
static void model_exit(void)
printk("exit!\\n");
kthread_stop(main_task);
module_init(model_init);
module_exit(model_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyong");
使用dmesg查看打印输出如下
[ 2369.599934] server run 0
[ 2369.599938] index 0
[ 2370.609331] server run 1
[ 2370.609335] index 1
[ 2371.632714] server run 2
[ 2371.632716] index 2
[ 2372.656413] server run 3
[ 2372.656415] index 3
[ 2373.680923] server run 4
[ 2373.680927] index 4
[ 2374.705357] server run 5
[ 2374.705362] index 5
[ 2375.729315] server run 6
[ 2375.729320] index 6
[ 2376.752834] server run 7
[ 2376.752838] index 7
[ 2377.777063] server run 8
[ 2377.777069] index 8
[ 2378.801040] server run 9
[ 2378.801042] index 9
[ 2379.827048] server run 10
四、自定义工作队列
函数含义与默认差不多
create_workqueue(name)
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)
void flush_workqueue(struct workqueue_struct *wq)
void destroy_workqueue(struct workqueue_struct *wq)
自定义示例
实验现象:10秒钟后执行延迟函数,使用dmesg 查看输出信息
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
static struct workqueue_struct *wq; /*声明一个工作队列*/
static struct delayed_work d_work; /*声明一个延期工作实例*/
//工作队列延迟处理函数
void print_hello(struct work_struct *work)
printk("print workqueue` ...\\n");
static int __init wq_init(void)
int ret = 0;
wq = create_workqueue("test_wq"); //创建工作队列
if (!wq)
printk("create workqueue failed \\n");
return -1;
INIT_DELAYED_WORK(&d_work, print_hello);//动态延迟初始化工作队列
ret = queue_delayed_work(wq, &d_work, msecs_to_jiffies(10000)); //向工作队列添加工作项
return 0;
static void __exit wq_exit(void)
int ret = 0;
printk("test_wy exit\\n");
ret = cancel_delayed_work(&d_work); /*取消工作项*/
flush_workqueue(wq); /*刷新工作队列*/
destroy_workqueue(wq); /*销毁工作队列*/
module_init(wq_init);
module_exit(wq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyong");
MODULE_DESCRIPTION("workqueue driver");
Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m:=main.o
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko
endif
(内核免费课程链接:https://ke.qq.com/course/4032547?flowToken=1042391)
以上是关于linux内核源码分析中断work_queue的主要内容,如果未能解决你的问题,请参考以下文章