欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

中断下半部的工作队列机制

程序员文章站 2022-03-22 17:31:53
...

工作队列处理机制

1.三个重要结构体:

1.1 struct workqueue_struct:

struct workqueue_struct {
	unsigned int		flags;		/* W: WQ_* flags */
	union {
		struct cpu_workqueue_struct __percpu	*pcpu;
		struct cpu_workqueue_struct		*single;
		unsigned long				v;
	} cpu_wq;				/* I: cwq's */
	struct list_head	list;		/* W: list of all workqueues */

	struct mutex		flush_mutex;	/* protects wq flushing */
	int			work_color;	/* F: current work color */
	int			flush_color;	/* F: current flush color */
	atomic_t		nr_cwqs_to_flush; /* flush in progress */
	struct wq_flusher	*first_flusher;	/* F: first flusher */
	struct list_head	flusher_queue;	/* F: flush waiters */
	struct list_head	flusher_overflow; /* F: flush overflow list */

	mayday_mask_t		mayday_mask;	/* cpus requesting rescue */
	struct worker		*rescuer;	/* I: rescue worker */

	int			nr_drainers;	/* W: drain in progress */
	int			saved_max_active; /* W: saved cwq max_active */
#ifdef CONFIG_LOCKDEP
	struct lockdep_map	lockdep_map;
#endif
	char			name[];		/* I: workqueue name */
};

1.2. struct worker

struct worker {
	/* on idle list while idle, on busy hash table while busy */
	union {
		struct list_head	entry;	/* L: while idle */
		struct hlist_node	hentry;	/* L: while busy */
	};

	struct work_struct	*current_work;	/* L: work being processed */
	struct cpu_workqueue_struct *current_cwq; /* L: current_work's cwq */
	struct list_head	scheduled;	/* L: scheduled works */
	struct task_struct	*task;		/* I: worker task */
	struct global_cwq	*gcwq;		/* I: the associated gcwq */
	/* 64 bytes boundary on 64bit, 32 on 32bit */
	unsigned long		last_active;	/* L: last active timestamp */
	unsigned int		flags;		/* X: flags */
	int			id;		/* I: worker id */
	struct work_struct	rebind_work;	/* L: rebind worker to cpu */
};

1.3. struct work_struct

struct work_struct {
	atomic_long_t data;		//传参数据
	struct list_head entry;		//链表结构,将任务挂载到queue的挂载点
	work_func_t func;		//函数指针
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
};

2.为什么要有workqueue机制

Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。workqueue是内核中实现简单而有效的机制,显然简化了内核daemon的创建,方便了用户的编程

daemon与服务的关系:我们系统为了某些功能必须要提供一些服务,而如何产生这些服务?那就是需要一个程序来运行产生这个服务。那么这个程序相对于这个服务来说就是daemon。daemon与服务是两个不同的东西:一个服务需要daemon在后台中运行,没有这个daemon就不会有这个服务。用ps或是top命令查看进程时,会看到很多xxxd的进程。这就是一些daemon的进程

3. workqueue的实现原理

如下图:

中断下半部的工作队列机制

步骤:

  • 创建工作队列

  • 创建工作

  • 调度工作(把工作加入到链表中)

    3.1创建工作队列

    方法:

    1. create_singlethread_workqueue(name)

      这个函数完成了workqueue的初始化。上图中的cwq是一per-CPU类型的地址空间。对于create_singlethread_workqueue而言,即使是对于多CPU系统,内核也只负责创建一个worker_thread内核进程。该内核进程被创建之后,会先定义一个图中的wait节点,然后在一循环体中检查cwq中的worklist,如果该队列为空,那么就会把wait节点加入到cwq中的more_work中,然后休眠在该等待队列中。

      调用这个函数之后,会创建一个内核线程去判断是否工作链表中有工作要做

      2.create_workqueue

      相对于create_singlethread_workqueue, create_workqueue同样会分配一个wq的工作队列,但是不同之处在于,对于多CPU系统而言,对每一个CPU,都会为之创建一个per-CPU的cwq结构,对应每一个cwq,都会生成一个新的worker_thread进程。但是当用queue_work向cwq上提交work节点时,是哪个CPU调用该函数,那么便向该CPU对应的cwq上的worklist上增加work节点。

    3.2 创建工作

    方法:

  • 静态:DECLARE_WORK(name,void (*func) (void *), void *data);在编译时静态地创建work_struct

  • 动态: INIT_WORK(structwork_struct *work, void(*func) (void *), void *data);

    3.3调度工作

    方法:

    1. queue_work(struct workqueue_struct*struct work_struct*//把工作插入指定的工作队列
    2. queue_delayed_work	//延迟调度执行一个指定workqueue中的任务,功能与queue_work类似,输入参数多了一个delay。
    3. schedule_work(struct work_struct*//调度执行一个具体的任务,执行的任务将会被挂入Linux系统提供的workqueue:keventd_wq
    4. schedule_delayed_work	//延迟一定时间去执行一个具体的任务,功能与schedule_work类似
    

    这些函数内部除了把工作结构体加到工作链表以外,还会唤醒内核线程来处理。

例如Driver调用queue_work(struct workqueue_struct *wq, struct work_struct *work)向wq中加入工作节点。work会依次加在cwq->worklist所指向的链表中。queue_work向cwq->worklist中加入一个work节点,同时会调用wake_up来唤醒休眠在cwq->more_work上的worker_thread进程。

当worker_thread再次被调度,开始处理cwq->worklist中的所有work节点…当所有work节点处理完毕,worker_thread重新将wait节点加入到cwq->more_work,然后再次休眠在该等待队列中直到Driver调用queue_work…

4.代码示例

#include <linux/module.h>  
#include <linux/init.h>  
#include <linux/workqueue.h>  
  
static struct workqueue_struct *queue=NULL;  
static struct work_struct   work;  
  
staticvoid work_handler(struct work_struct *data)  
{  
       printk(KERN_ALERT"work handler function.\n");  
}  
  
static int __init test_init(void)  
{  
      queue=create_singlethread_workqueue("hello world");/*创建一个单线程的工作队列*/  
      if (!queue)  
            goto err;  
  
       INIT_WORK(&work,work_handler);  //动态创建工作,联系工作内容
       schedule_work(&work);  
  
      return0;  
err:  
      return-1;  
}  
  
static   void __exit test_exit(void)  
{  
       destroy_workqueue(queue);  
}  
MODULE_LICENSE("GPL");  
module_init(test_init);  
module_exit(test_exit);  

参考资料

https://www.cnblogs.com/sky-heaven/p/5847520.html

相关标签: 驱动