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