为什么 wait 为空时只有 __add_wait_queue(q, wait)?

Why only __add_wait_queue(q, wait) when wait is empty?

https://elixir.bootlin.com/linux/v4.5/source/kernel/sched/wait.c#L172

void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
{
    unsigned long flags;

    wait->flags &= ~WQ_FLAG_EXCLUSIVE;
    spin_lock_irqsave(&q->lock, flags);
    if (list_empty(&wait->task_list))
        __add_wait_queue(q, wait);
    set_current_state(state);
    spin_unlock_irqrestore(&q->lock, flags);
}

在上面的代码中,我们可以看到 __add_wait_queue(q, wait) 只在 list_empty(&wait->task_list) 是真的。

为什么&wait->task_list不为空,那么wait不需要加q (wait_queue_head_t)?

这是否意味着如果 wait (wait_queue_t) 已经在 q (wait_queue_head_t ) 然后不要改变它?

Does that mean if wait (wait_queue_t) already in a q (wait_queue_head_t ), then don't change it?

是的,分支

if (list_empty(&wait->task_list))
    __add_wait_queue(q, wait);

意味着,仅当 wait 尚未属于任何队列时,才将 wait 添加到等待队列 q

否则,如果判断wait已经属于(某个)等待队列,则认为wait具体属于q,不添加再次.


对象调用list_empty函数有一些特殊之处,对象可以是列表的元素(不是列表的头部)。

list_empty 始终 returns false,如果对象属于列表。

但是如果对象不属于任何列表,那么return值一般是未指定(大多数情况下是 false 也是)。

异常是一个对象,用 INIT_LIST_HEAD 函数或 LIST_HEAD_INIT 宏初始化或用 list_del_init 函数从列表中删除:在这种情况下 list_empty returns true 有保证。

如果在wait.h头中查找INIT_LIST_HEADLIST_HEAD_INITlist_del_init的用法,则可以发现prepare_to_wait函数是只允许 wait 对象:

  1. 使用 DEFINE_WAIT 宏或 DEFINE_WAIT_* 宏之一创建。
  2. 使用 init_wait 函数初始化,例如调用来自 wait_event_* 宏之一。
  3. 已传递给 finish_wait 函数。

但是prepare_to_wait函数不能用于wait对象,用DECLARE_WAITQUEUE宏创建:这个宏初始化task_list 字段与 {NULL, NULL},所以 list_empty 会 return false(好像等待对象已经添加到等待队列中)。