为什么 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_HEAD
、LIST_HEAD_INIT
或list_del_init
的用法,则可以发现prepare_to_wait
函数是只允许 wait
对象:
- 使用
DEFINE_WAIT
宏或 DEFINE_WAIT_*
宏之一创建。
- 使用
init_wait
函数初始化,例如调用来自 wait_event_*
宏之一。
- 已传递给
finish_wait
函数。
但是prepare_to_wait
函数不能用于wait
对象,用DECLARE_WAITQUEUE
宏创建:这个宏初始化task_list
字段与 {NULL, NULL}
,所以 list_empty
会 return false(好像等待对象已经添加到等待队列中)。
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 aq
(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_HEAD
、LIST_HEAD_INIT
或list_del_init
的用法,则可以发现prepare_to_wait
函数是只允许 wait
对象:
- 使用
DEFINE_WAIT
宏或DEFINE_WAIT_*
宏之一创建。 - 使用
init_wait
函数初始化,例如调用来自wait_event_*
宏之一。 - 已传递给
finish_wait
函数。
但是prepare_to_wait
函数不能用于wait
对象,用DECLARE_WAITQUEUE
宏创建:这个宏初始化task_list
字段与 {NULL, NULL}
,所以 list_empty
会 return false(好像等待对象已经添加到等待队列中)。