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_headpwqs;/* WR: all pwqs of this wq */struct list_headlist;/* PR: list of all workqueues */struct mutexmutex;/* protects this wq */intwork_color;/* WQ: current work color */intflush_color;/* WQ: current flush color */atomic_tnr_pwqs_to_flush; /* flush in progress */struct list_headmaydays;/* MD: pwqs requesting rescue */struct worker*rescuer;/* MD: rescue worker */intnr_drainers;/* WQ: drain in progress */intsaved_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 */charname[WQ_NAME_LEN]; /* I: workqueue name */struct rcu_headrcu;/* hot fields used during command issue, aligned to cacheline */unsigned intflags ____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 #include #include #include #include #include #include #include #include #include #include #define BUF_SIZE 1024struct 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 #include #include #include 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.oelseKERNELDIR:=/lib/modules/$(shell uname -r)/buildPWD:=$(shell pwd)default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesclean: rm -rf *.o *.mod.c *.mod.o *.koendif
(内核免费课程链接:https://ke.qq.com/course/4032547?flowToken=1042391)