linux等待队列

一.头文件

#include <linux/wait.h>

二.结构体

1.等待队列头

struct __wait_queue_head {
	spinlock_t lock;
	struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

2.等待队列

struct __wait_queue {
	unsigned int flags;
	void *private;
	wait_queue_func_t func;
	struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;


三.初始化

1.等待队列头

定义声明等待队列头

#define DECLARE_WAIT_QUEUE_HEAD(name) \
	wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)

定义了一个等待队列头,并初始化其成员

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

2.等待队列

定义声明等待队列

#define DECLARE_WAITQUEUE(name, tsk)				\
	wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)

初始化其成员

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

四.添加与移除等待队列

1.添加等待队列

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
	unsigned long flags;

	wait->flags &= ~WQ_FLAG_EXCLUSIVE;
	spin_lock_irqsave(&q->lock, flags);
	__add_wait_queue(q, wait);
	spin_unlock_irqrestore(&q->lock, flags);
}

__add_wait_queue本质上就是添加等待队列的task_list进等待队列头的task_list为首项的list链表

static inline void __add_wait_queue_tail(wait_queue_head_t *head, wait_queue_t *new)
{
	list_add_tail(&new->task_list, &head->task_list);
}

2.移除等待队列

void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
	unsigned long flags;

	spin_lock_irqsave(&q->lock, flags);
	__remove_wait_queue(q, wait);
	spin_unlock_irqrestore(&q->lock, flags);
}

__remove_wait_queue本质上就是从等待队列头的task_list为首项的list链表中移除等待队列的task_list

static inline void __remove_wait_queue(wait_queue_head_t *head,wait_queue_t *old)
{
	list_del(&old->task_list);
}

五.等待,唤醒,睡眠
1.等待

1.1 wait_event 等待事件发生,不可中断

#define wait_event(wq, condition) 					\
do {								\
	if (condition)	 					\	//唤醒的条件为真,则退出
		break;						\
	__wait_event(wq, condition);				\
} while (0)

__wait_event

#define __wait_event(wq, condition) 					\
do {								\
	DEFINE_WAIT(__wait);					\
								\
	for (;;) {						\
		prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);	\	//TASK_UNINTERRUPTIBLE标明不可中断
		if (condition)					\	//唤醒的条件为真,则退出for循环
			break;					\
		schedule();					\	//进入调度
	}							\
	finish_wait(&wq, &__wait);					\	//设置进程为TASK_RUNNING,并移除等待队列中的队列项
} while (0)

1.2 wait_event_interruptible 等待事件发生,可中断

#define wait_event_interruptible(wq, condition)			\
({								\
	int __ret = 0;						\
	if (!(condition))						\	//条件为真则退出
		__wait_event_interruptible(wq, condition, __ret);	\	
	__ret;							\
})

__wait_event_interruptible

#define __wait_event_interruptible(wq, condition, ret)			\
do {								\
	DEFINE_WAIT(__wait);					\
								\
	for (;;) {						\
		prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);	\	//TASK_INTERRUPTIBLE标明可中断
		if (condition)					\	//唤醒的条件为真,则退出for循环
			break;					\
		if (!signal_pending(current)) {			\	//检测当前进程是否有信号要处理
			schedule();				\	//进入调度
			continue;					\
		}						\
		ret = -ERESTARTSYS;				\
		break;						\
	}							\
	finish_wait(&wq, &__wait);					\	//设置进程为TASK_RUNNING,并移除等待队列中的队列项
} while (0)

1.3 wait_event_timeout 超时等待事件,不可中断

#define wait_event_timeout(wq, condition, timeout)			\
({								\
	long __ret = timeout;					\
	if (!(condition)) 						\	//等待条件为真则退出
		__wait_event_timeout(wq, condition, __ret);		\	
	__ret;							\
})

__wait_event_timeout

#define __wait_event_timeout(wq, condition, ret)			\
do {								\
	DEFINE_WAIT(__wait);					\
								\
	for (;;) {						\
		prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);	\	//TASK_UNINTERRUPTIBLE标明不可中断
		if (condition)					\	//唤醒的条件为真,则退出for循环
			break;					\
		ret = schedule_timeout(ret);			\	//调度,并设置超时值
		if (!ret)						\	//超时则退出
			break;					\
	}							\
	finish_wait(&wq, &__wait);					\	//设置进程为TASK_RUNNING,并移除等待队列中的队列项	
} while (0)

1.4 wait_event_interruptible_timeout 超时等待事件,可中断

#define wait_event_interruptible_timeout(wq, condition, timeout)	\
({								\
	long __ret = timeout;					\
	if (!(condition))						\	//等待条件为真则退出
		__wait_event_interruptible_timeout(wq, condition, __ret); \	
	__ret;							\
})

__wait_event_interruptible_timeout

#define __wait_event_interruptible_timeout(wq, condition, ret)		\
do {								\
	DEFINE_WAIT(__wait);					\
								\
	for (;;) {						\
		prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);	\	//TASK_INTERRUPTIBLE标明可中断
		if (condition)					\	//唤醒的条件为真,则退出for循环
			break;					\
		if (!signal_pending(current)) {			\	//检测当前进程是否有信号要处理
			ret = schedule_timeout(ret);		\	//调度,并设置超时值
			if (!ret)					\	//超时则退出
				break;				\
			continue;					\	
		}						\
		ret = -ERESTARTSYS;				\
		break;						\
	}							\
	finish_wait(&wq, &__wait);					\	//设置进程为TASK_RUNNING,并移除等待队列中的队列项
} while (0)


2.唤醒
2.1 wake_up唤醒不可中断的等待队列

#define wake_up(x)   __wake_up(x, TASK_NORMAL, 1, NULL)

衍生的其他宏

#define wake_up_nr(x, nr)		__wake_up(x, TASK_NORMAL, nr, NULL)
#define wake_up_all(x)			__wake_up(x, TASK_NORMAL, 0, NULL)
#define wake_up_locked(x)		__wake_up_locked((x), TASK_NORMAL)

2.2 wake_up_interruptible唤醒可中断的等待队列

#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)

 

两个宏最终都调用__wake_up

void __wake_up(wait_queue_head_t *q, unsigned int mode,int nr_exclusive, void *key)
{
	unsigned long flags;

	spin_lock_irqsave(&q->lock, flags);
	__wake_up_common(q, mode, nr_exclusive, 0, key);	//-->__wake_up_common
	spin_unlock_irqrestore(&q->lock, flags);
}

__wake_up_common

static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,int nr_exclusive, int wake_flags, void *key)
{
	wait_queue_t *curr, *next;

	list_for_each_entry_safe(curr, next, &q->task_list, task_list) {	//遍历等待队列表
		unsigned flags = curr->flags;	
		//调用其等待队列项的func方法,-->default_wake_function
		if (curr->func(curr, mode, wake_flags, key) &&(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
			break;
	}
}

default_wake_function

int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,void *key)
{
	return try_to_wake_up(curr->private, mode, wake_flags);	//-->try_to_wake_up
	}

try_to_wake_up

static int try_to_wake_up(struct task_struct *p, unsigned int state,int wake_flags)
{
	int cpu, orig_cpu, this_cpu, success = 0;
	unsigned long flags;
	unsigned long en_flags = ENQUEUE_WAKEUP;
	struct rq *rq;
	this_cpu = get_cpu();

	smp_wmb();
	rq = task_rq_lock(p, &flags);
	if (!(p->state & state))
		goto out;

	if (p->se.on_rq)
		goto out_running;

	cpu = task_cpu(p);
	orig_cpu = cpu;

#ifdef CONFIG_SMP
	if (unlikely(task_running(rq, p)))
		goto out_activate;

	if (task_contributes_to_load(p)) {
		if (likely(cpu_online(orig_cpu)))
			rq->nr_uninterruptible--;
		else
			this_rq()->nr_uninterruptible--;
	}
	p->state = TASK_WAKING;

	if (p->sched_class->task_waking) {
		p->sched_class->task_waking(rq, p);
		en_flags |= ENQUEUE_WAKING;
	}

	cpu = select_task_rq(rq, p, SD_BALANCE_WAKE, wake_flags);
	if (cpu != orig_cpu)
		set_task_cpu(p, cpu);
	__task_rq_unlock(rq);

	rq = cpu_rq(cpu);
	raw_spin_lock(&rq->lock);

	WARN_ON(task_cpu(p) != cpu);
	WARN_ON(p->state != TASK_WAKING);

#ifdef CONFIG_SCHEDSTATS
	schedstat_inc(rq, ttwu_count);
	if (cpu == this_cpu)
		schedstat_inc(rq, ttwu_local);
	else {
		struct sched_domain *sd;
		for_each_domain(this_cpu, sd) {
			if (cpumask_test_cpu(cpu, sched_domain_span(sd))) {
				schedstat_inc(sd, ttwu_wake_remote);
				break;
			}
		}
	}
#endif /* CONFIG_SCHEDSTATS */

out_activate:
#endif /* CONFIG_SMP */
	ttwu_activate(p, rq, wake_flags & WF_SYNC, orig_cpu != cpu, cpu == this_cpu, en_flags);	//最终调用activate_task激活等待进程
	success = 1;
out_running:
	ttwu_post_activation(p, rq, wake_flags, success);
out:
	task_rq_unlock(rq, &flags);
	put_cpu();

	return success;
}

3.睡眠

3.1 sleep_on 睡眠,不可中断

void __sched sleep_on(wait_queue_head_t *q)
{
	sleep_on_common(q, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}

3.2 interruptible_sleep_on 睡眠,可中断

void __sched interruptible_sleep_on(wait_queue_head_t *q)
{
	sleep_on_common(q, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}

3.3 sleep_on_timeout 超时睡眠,不可中断

long __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
{
	return sleep_on_common(q, TASK_UNINTERRUPTIBLE, timeout);
}

3.4 interruptible_sleep_on_timeout 超时睡眠,可中断

long __sched interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
{
	return sleep_on_common(q, TASK_INTERRUPTIBLE, timeout);
}

睡眠api最终都会调用sleep_on_common

static long __sched
sleep_on_common(wait_queue_head_t *q, int state, long timeout)
{
	unsigned long flags;
	wait_queue_t wait;

	init_waitqueue_entry(&wait, current);	//初始化等待队列项

	__set_current_state(state);		//设置当前进程的状态TASK_UNINTERRUPTIBLE、TASK_INTERRUPTIBLE

	spin_lock_irqsave(&q->lock, flags);
	__add_wait_queue(q, &wait);	//添加等待队列项
	spin_unlock(&q->lock);
	timeout = schedule_timeout(timeout);	//调度,设置超时值
	spin_lock_irq(&q->lock);
	__remove_wait_queue(q, &wait);	//移除等待队列项
	spin_unlock_irqrestore(&q->lock, flags);

	return timeout;
}


六.整理

//等待队列头
wait_queue_head_t	
//初始化等待队列头
DECLARE_WAIT_QUEUE_HEAD(name)

//等待队列项
wait_queue_t	
//初始化等待队列项
DECLARE_WAITQUEUE(name, tsk)	
//添加移除等待队列项
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)		//添加等待队列项
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)	//移除等待队列项
//等待事件
wait_event(wq, condition) 						//等待事件,不可中断	
wait_event_interruptible(wq, condition)				//等待事件,可中断		 
wait_event_timeout(wq, condition, timeout)				//超时等待,不可中断
wait_event_interruptible_timeout(wq, condition, timeout)		//超时等待,可中断	
//唤醒事件
wake_up(x)							//唤醒事件,不可中断
wake_up_interruptible(x)						//唤醒事件,可中断
//等待队列上睡眠
void __sched sleep_on(wait_queue_head_t *q)				//睡眠,不可中断
void __sched interruptible_sleep_on(wait_queue_head_t *q)		//睡眠,可中断
long __sched sleep_on_timeout(wait_queue_head_t *q, long timeout) 	//超时睡眠,不可中断
long __sched interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout) //超时睡眠,可中断

等待和睡眠本质上在于有无条件,睡眠属于旧版本内核的东西,很少使用到











 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值