内核等待队列相关操作(kernel waitqueue) (一)

一.介绍

  1. linux内核中等待队列应用非常广泛,比如进程调度或者一些中断处理下半部处理,对于进程来说,当进程在等待某些条件时,希望等待条件满足的进程把自己放在相应的队列,并放弃控制权给其他进程,当条件被满足时,由内核唤醒.
  2. 等待队列由循环链表实现,其元素包括指向进程描述符的指针。每个等待队列都有一个等待队列头(wait queue head),等待队列头是一个类型为wait_queue_head_t的数据结构.

二.队列结构及接口介绍

  • 队列相关信息在 include/linux/wait.h 文件中
  • 队列头结构及初始化
struct wait_queue_head {
    spinlock_t        lock;
    struct list_head    head;
};
一个双向链表,一个自旋锁

#define __WAIT_QUEUE_HEAD_INITIALIZER(name) {					\
	.lock		= __SPIN_LOCK_UNLOCKED(name.lock),			\
	.head		= { &(name).head, &(name).head } }

#define DECLARE_WAIT_QUEUE_HEAD(name) \
	struct wait_queue_head name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
初始化队列头及自旋锁
  • 队列项结构及实始化
struct wait_queue_entry {
	unsigned int		flags;
	void			*private;
	wait_queue_func_t	func;
	struct list_head	entry;
};
flags: 包含跟进程相关的一系列标志,比如TASK_INTERRUPTIBLE, TASK_UNINTERRUPTIBLE,TASK_KILLABLE,WQ_FLAG_EXCLUSIVE等等
private:是当前任务结构体,大多数情况是current
func:为唤醒回调函数
entry:挂到队列头的结点

#define __WAITQUEUE_INITIALIZER(name, tsk) {					\
	.private	= tsk,							\
	.func		= default_wake_function,				\
	.entry		= { NULL, NULL } }

#define DECLARE_WAITQUEUE(name, tsk)						\
	struct wait_queue_entry name = __WAITQUEUE_INITIALIZER(name, tsk)
实始化队列结点,即wait_queue_entry
1. 创建一个entry,结点
2. 把一个任务赋值给private, 可以是当前任务,也可以是其他任务.
3. 挂载默认唤醒回调函数.
4. 初始化双向链表结点
  • 将队列结点挂载到队列中
static inline void __add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
{
	list_add(&wq_entry->entry, &wq_head->head);
}

/*
 * Used for wake-one threads:
 */
static inline void
__add_wait_queue_exclusive(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
{
	wq_entry->flags |= WQ_FLAG_EXCLUSIVE;
	__add_wait_queue(wq_head, wq_entry);
}

将对队列结点挂入队列中,就是一个链表添加操作
这里有两个操作,一个带WQ_FLAG_EXCLUSIVE标志,一个不带
WQ_FLAG_EXCLUSIVE:表示独占唤醒信号,即唤醒一个等待的任务.
不带此标志:代表唤醒所有等待的任务
  • 等待唤醒和唤醒接口

#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd)		\
({										\
	__label__ __out;							\
	struct wait_queue_entry __wq_entry;					\
	long __ret = ret;	/* explicit shadow */				\
										\
	init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0);	\
	for (;;) {								\
		long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\
										\
		if (condition)							\
			break;							\
										\
		if (___wait_is_interruptible(state) && __int) {			\
			__ret = __int;						\
			goto __out;						\
		}								\
										\
		cmd;								\
	}									\
	finish_wait(&wq_head, &__wq_entry);					\
__out:	__ret;									\
})

#define wait_event(wq_head, condition)						\
do {										\
	might_sleep();								\
	if (condition)								\
		break;								\
	__wait_event(wq_head, condition);					\
} while (0)

__wait__event: 主要做了四件事:
1. 判断condition是否满足,如果满足,返回,不满足向下执行等待条件满足
2.创建队列结点并实始化,跟DECLARE_WAITQUEUE做的工作一样.
3.添加队列结点到队列,并设置当前任务状态TASK_INTERRUPTIBLE等相关状态
4.放度控制权,即调用schedule();


void __wake_up(struct wait_queue_head *wq_head, unsigned int mode,
			int nr_exclusive, void *key)
{
	__wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key);
}
#define wake_up(x)			__wake_up(x, TASK_NORMAL, 1, NULL)
__wake_up: 当条件满足时,唤醒wait_event等待的任务.
  • 其他的等待与唤醒接口
等待与唤醒条件或方式不一样,根据需要选择即可
#define wait_event_freezable(wq_head, condition)	
#define wait_event_timeout(wq_head, condition, timeout)	
#define wait_event_interruptible(wq_head, condition)
#define wait_event_killable(wq_head, condition)	
...

#define wake_up_interruptible(x)	__wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)

#define wake_up_interruptible_nr(x, nr)	__wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)
#define wake_up_interruptible_all(x)	__wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
#define wake_up_interruptible_sync(x)	__wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
...

三.整体结构图如下

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值