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的主要内容,如果未能解决你的问题,请参考以下文章

结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程

linux源码分析

Linux 内核中断内幕

鸿蒙轻内核M核源码分析:中断Hwi

“Linux内核分析”实验二报告

鸿蒙轻内核M核源码分析:中断Hwi