• 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
    ", current->pid, current->comm);
    	printk(KERN_INFO "[work]=> sleep 1 seconds
    ");
    	set_current_state(TASK_INTERRUPTIBLE);
    	schedule_timeout(1 * HZ); //Wait 1 seconds
    	printk(KERN_INFO "[work]=> data is: %d  %s
    ", 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/

  • 相关阅读:
    Java实现 LeetCode 667 优美的排列 II(暴力)
    Java实现 LeetCode 665 非递减数列(暴力)
    Java实现 LeetCode 665 非递减数列(暴力)
    Java实现 LeetCode 665 非递减数列(暴力)
    Java实现洛谷 P1873 砍树(StreamTokenizer+IO+二分)
    PHP RESTful
    PHP 获取图像宽度与高度
    PHP imagecolorclosesthwb
    PHP imagecolorclosestalpha
    PHP imagecolorclosest
  • 原文地址:https://www.cnblogs.com/unclemac/p/12783404.html
Copyright © 2020-2023  润新知