一.头文件
#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) //超时睡眠,可中断
等待和睡眠本质上在于有无条件,睡眠属于旧版本内核的东西,很少使用到