【linux kernel】linux中断管理—workqueue工作队列

linux中断管理—workqueue工作队列


(注)本文所有代码均出自linux版本: 4.1.15

一、workqueue工作队列简介

工作队列是除软中断和tasklet以外最常用的一种下半部机制,其基本原理是:把work(需要推迟执行的函数)交由一个内核线程来执行,工作队列总是在进程上下文执行。

​ 工作队列的优点:

  • 因工作队列在进程下文中执行,因此工作队列允许重新调度和睡眠,是异步执行的进程上下文。
  • 解决了如果软中断和tasklet执行时间过长会导致系统实时性下降等问题。
(1-1)work_struct工作

linux内核中使用work_struct结构体来表示一个工作,如下定义(/inlcude/linux/workqueue.h):

struct work_struct {
	atomic_long_t data;
	struct list_head entry;
	work_func_t func;
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
};
(1-2)workqueue工作队列

把工作(包括该工作任务的执行回调函数)添加到一个队列,称为workqueue,即工作队列,然后通过worker-pool中的内核工作线程(worker)去执行这个回调函数。工作队列使用workqueue_struct结构体来表示,定义如下(/kernel/workqueue.c):

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 wq_flusher	*first_flusher;	/* WQ: first flusher */
	struct list_head	flusher_queue;	/* WQ: flush waiters */
	struct list_head	flusher_overflow; /* WQ: flush overflow list */

	struct list_head	maydays;	/* MD: pwqs requesting rescue */
	struct worker		*rescuer;	/* I: rescue worker */

	int			nr_drainers;	/* WQ: drain in progress */
	int			saved_max_active; /* WQ: saved pwq max_active */

	struct workqueue_attrs	*unbound_attrs;	/* WQ: only for unbound wqs */
	struct pool_workqueue	*dfl_pwq;	/* WQ: only for unbound wqs */

#ifdef CONFIG_SYSFS
	struct wq_device	*wq_dev;	/* I: for sysfs interface */
#endif
#ifdef CONFIG_LOCKDEP
	struct lockdep_map	lockdep_map;
#endif
	char			name[WQ_NAME_LEN]; /* I: workqueue name */

	/*
	 * Destruction of workqueue_struct is sched-RCU protected to allow
	 * walking the workqueues list without grabbing wq_pool_mutex.
	 * This is used to dump all workqueues from sysrq.
	 */
	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[]; /* FR: unbound pwqs indexed by node */
};
(1-3)worker工作者线程

​ linux 内核使用工作者线程(worker thread)来处理工作队列中的各个工作,linux 内核使用
worker 结构体表示工作者线程,worker 结构体定义如下(/kernel/workqueue_internal.h):

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;	/*当前正在处理的work */
	work_func_t		current_func;	/* 当前正在执行的work回调函数 */
	struct pool_workqueue	*current_pwq; /* 当前work所属的pool_workqueue*/
	bool			desc_valid;	/* ->desc is valid */
	struct list_head	scheduled;	/* 所有被调度并正准备执行的work都将加入到该链表中*/

	/* 64 bytes boundary on 64bit, 32 on 32bit */

	struct task_struct	*task;		/* 该工作线程的task_struct  */
	struct worker_pool	*pool;		/* 该工作线程所属的worker_pool */
						/* L: for rescuers */
	struct list_head	node;		/* worker挂入的 链表 pool->workers */
						/* A: runs through worker->node */

	unsigned long		last_active;	/* L: last active timestamp */
	unsigned int		flags;		/* X: flags */
	int			id;		/* 工作线程的id */

	/*
	 * Opaque string set with work_set_desc().  Printed out with task
	 * dump for debugging - WARN, BUG, panic or sysrq.
	 */
	char			desc[WORKER_DESC_LEN];

	/* used only by rescuers to point to the target workqueue */
	struct workqueue_struct	*rescue_wq;	/* I: the workqueue to rescue */
};
二、workqueue工作队列的使用

​ 每一个worker工作线程中都有一个工作队列,工作线程处理自己工作队列中的所有工作。

在实际开发中,推荐使用默认的workqueue·工作队列,而不是新创建workqueue。使用方法如下:

​ 直接定义一个work_struct结构体变量,然后使用INIT_WORK宏来完成初始化工作,INIT_WORK定义如下:

#define INIT_WORK(_work, _func)

_work表示要初始化的工作,_func是工作对应的处理函数。

也可以使用 DECLARE_WORK 宏一次性完成工作的创建和初始化,宏定义如下:

#define DECLARE_WORK(n, f)

​ n 表示定义的工作(work_struct),f 表示工作对应的处理函数。和 tasklet 一样,工作也是需要调度才能运行的,工作的调度函数为schedule_work(),函数原型如下所示:

bool schedule_work(struct work_struct *work)

使用cancel_work_sync()取消一个工作,函数原型如下所示:

bool cancel_work_sync(struct work_struct *work)

当然也可以自己创建一个workqueue,特别是网络子系统、块设备子系统情况下等。具体步骤如下:

  • 使用alloc_workqueue()创建新的workqueue。
  • 使用INIT_WORK()宏声明一个work和该work的回调函数。
  • 使用queue_work()在新的workqueue上调度一个work。
  • 使用flush_workqueue()去flush 工作队列上的所有work。

除此之外,linux内核还提供了一个workqueue机制与timer机制相结合的延时机制—delayed_work

三、代码示例

//定义一个工作(work)
static struct work_sturct my_work;

//定义一个工作处理函数
void my_work_func(struct work_struct *work)
{
    /*.......*/
}


//定义中断处理函数
irqreturn_t  key_handler(int irq,void *dev_id)
{
    //.........
    
    //调度work
    shcedule_work(&my_work);
    
   // ......
}

/* 驱动入口函数
*/
static int __init my_demo_init(void)
{
    //...
    
	//初始化work
    INIT_WORK(&my_work,my_work_func);
    
    //注册中断处理 函数
    request_irq(xxx_irq,key_handler,0,"xxxx",&xxx_dev);
    
    //....
}

static void __exit my_demo_exit(void)
{
    //执行一些释放操作
    //....
}


module_init(my_demo_init);
module_exit(my_demo_exit);
    
MODULE_LICENSE("GPL");
MODULE_AUTHOR("iriczhao");

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iriczhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值