Linux 内核工作队列之work_struct 学习总结
Posted 小麦大叔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 内核工作队列之work_struct 学习总结相关的知识,希望对你有一定的参考价值。
前言
编写Linux驱动的时候对于work_struct
的使用还是很普遍的,很早之前就在阅读驱动源码的时候就看到了它的踪影,根据其命名大概知道了它的具体作用,但是仍然不知所以,同时,伴随出现的还有delayed_work
以及workqueue_struct
,抱着知其然并知其所以然的态度,在这里归纳总结一下work_struct
,以及如何在驱动中使用,因为工作队列相对来说比较复杂,篇幅和能力有限,只能介绍相对重要的部分。
workqueue
内核里一直运行类似worker thread
,它会对工作队列中的work
进行处理,大致的工作流程原理可以参考下图所示;
在这里的work
则是work_struct
变量,并且绑定一个执行函数——typedef void (*work_func_t)(struct work_struct *work);
。在worker thread
中会对非空的工作队列进行工作队列的出队操作,并运行work
绑定的函数。
work_struct
work_struct
的数据结构如下,暂时我们还无法关注其原理,只关注如何去开启一个work
#include <linux/include/workqueue.h>
typedef void (*work_func_t)(struct work_struct *work);
struct work_struct
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
;
通过数据结构可以知道,每当我们定义一个work_struct
变量的时候,需要绑定一个work_func_t
类型的函数指针。
函数 | 功能 |
---|---|
INIT_WORK(_work, _func) | 初始化一个work |
INIT_WORK_ONSTACK(_work, _func) | 在栈上初始化一个work |
flush_work(struct work_struct *work); | 销毁一个work |
schedule_work(struct work_struct *work) | 调度一个work开始运行 |
例程
下面写了 一个demo,模块初始化之后会每隔5秒调度work开始运行,最终demo_work_func
会运行规定的次数,并打印传递的参数和进程信息。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/slab.h> //kmalloc kfree
#include <linux/sched.h>
#include <linux/delay.h>
static char data[] = "test for demo work";
struct work_ctx
struct work_struct real_work;
char *str;
int arg;
work_ctx;
struct work_ctx *demo_work;
static void demo_work_func(struct work_struct *work)
struct work_ctx *temp_work = container_of(work,struct work_ctx,real_work);
printk(KERN_INFO "[work]=> PID: %d; NAME: %s\\n", current->pid, current->comm);
printk(KERN_INFO "[work]=> sleep 1 seconds\\n");
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1 * HZ); //Wait 1 seconds
printk(KERN_INFO "[work]=> data is: %d %s\\n", temp_work->arg,temp_work->str);
static int __init demo_thread_init(void)
int count = 10;
demo_work = kmalloc(sizeof(*demo_work),GFP_KERNEL);
INIT_WORK(&demo_work->real_work, demo_work_func);
demo_work->str = data;
while(count--)
msleep(5000);
demo_work->arg = count;
schedule_work(&demo_work->real_work);
return 0;
module_init(demo_thread_init);
static void __exit demo_thread_exit(void)
flush_work(&demo_work->real_work);
kfree(demo_work);
module_exit(demo_thread_exit);
MODULE_LICENSE("GPL");
运行结果
[ 8.500146] [work]=> PID: 37; NAME: kworker/0:1
[ 8.500216] [work]=> sleep 1 seconds
[ 9.499783] [work]=> data is: 9 test for demo work
[ 13.503165] [work]=> PID: 37; NAME: kworker/0:1
[ 13.503213] [work]=> sleep 1 seconds
[ 14.503122] [work]=> data is: 8 test for demo work
[ 18.506493] [work]=> PID: 37; NAME: kworker/0:1
[ 18.506534] [work]=> sleep 1 seconds
[ 19.506460] [work]=> data is: 7 test for demo work
[ 23.509833] [work]=> PID: 37; NAME: kworker/0:1
[ 23.509874] [work]=> sleep 1 seconds
[ 24.510060] [work]=> data is: 6 test for demo work
[ 28.513161] [work]=> PID: 37; NAME: kworker/0:1
[ 28.513206] [work]=> sleep 1 seconds
[ 29.513121] [work]=> data is: 5 test for demo work
[ 33.516502] [work]=> PID: 37; NAME: kworker/0:1
[ 33.516545] [work]=> sleep 1 seconds
[ 34.516452] [work]=> data is: 4 test for demo work
[ 38.519819] [work]=> PID: 37; NAME: kworker/0:1
[ 38.519860] [work]=> sleep 1 seconds
[ 39.519782] [work]=> data is: 3 test for demo work
[ 43.523151] [work]=> PID: 37; NAME: kworker/0:1
[ 43.523191] [work]=> sleep 1 seconds
[ 44.523117] [work]=> data is: 2 test for demo work
[ 48.526495] [work]=> PID: 37; NAME: kworker/0:1
[ 48.526542] [work]=> sleep 1 seconds
[ 49.526444] [work]=> data is: 1 test for demo work
[ 53.539699] [work]=> PID: 37; NAME: kworker/0:1
[ 53.539763] [work]=> sleep 1 seconds
[ 54.542925] [work]=> data is: 0 test for demo work
参考
https://www.oreilly.com/library/view/understanding-the-linux/0596005652/ch04s08.html
https://kukuruku.co/post/multitasking-in-the-linux-kernel-workqueues/
以上是关于Linux 内核工作队列之work_struct 学习总结的主要内容,如果未能解决你的问题,请参考以下文章
Linux(内核剖析):26---中断下半部之(工作队列机制(workqueue_structcpu_workqueue_struct))