linux kernel version: 5.10
wait queue是linux中的一种等待-唤醒机制,可用于异步事件通知、进程间通信等场景。
其源码为:
kernel/sched/wait.c
include/linux/wait.h
如何使用wait queue机制呢?
1.定义struct wait_queue_head类型的变量my_wait_queue;以下两种方式是等效的;
1)DECLARE_WAIT_QUEUE_HEAD(my_wait_queue);
2)struct wait_queue_head my_wait_queue;
init_waitqueue_head(&my_wait_queue);
2. 在需要等待的进程中调用wait_event(或它的几个变种),等待直到条件event_occurred为真。
wait_event(my_wait_queue, event_occurred);
相关的变体定义如下:
wait_event(wq_head, condition) 等待期间进程处于不可中断睡眠状态
wait_event_timeout(wq_head, condition, timeout) 进程只等待限定的时间,以jiffies表示
wait_event_interruptible(wq_head, condition) 等待期间进程处于可中断睡眠状态
wait_event_interruptible_timeout(wq_head, condition, timeout) 进程只等待限定的时间,以jiffies表示
3.在发生event_occurred事件的进程中调用wake_up(或它的变种)唤醒等待的进程
event_occurred = true;
wake_up(&my_wait_queue);
相关的变体定义如下:后两个在文章后面说明
wake_up(&wq_head)
wake_up_interruptible(&wq_head)
wake_up_nr(&wq_head, nr) //nr为要唤醒的独占等待属性的进程个数wake_up_interruptible_nr(&wq_head, nr)
源码分析
结构体定义
wait_queue_head:This is a structure used to define a wait queue. It represents the head of the queue and contains information about the queue, such as the list of waiting tasks and the lock used to protect the queue.
wait_queue_entry:This is a structure used to define a task that is waiting on a wait queue. It contains information about the task.
In summary, a wait queue head is used to define a queue of waiting tasks, while a wait queue entry represents a single task that is waiting on the queue.
函数定义
__wait_event
wait_event及其变体最终都是调用__wait_event,只是入参的差异
#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd) \
({ \
__label__ __out; \
struct wait_queue_entry __wq_entry; \
long __ret = ret; /* explicit shadow */ \
\
//初始化wait_queue_entry类型的变量
init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0); \
for (;;) { \
/*如果state为可被中断且有挂起的signal信号,返回-ERESTARTSYS
*否则把wait_queue_entry添加到wait_queue_head链表中,并把进程状态设置为state
*这里只更改了进程状态,并没有执行调度。*/
long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\
\
//若condition满足,则跳出for循环,在finish_wait把进程状态设置为task_running
if (condition) \
break; \
\
if (___wait_is_interruptible(state) && __int) { \
__ret = __int; \
goto __out; \
} \
\
//cmd即为schedule()或schedule_timeout()或...,在这里触发进程调度
cmd; \
} \
//把进程状态设置为task_running,并将wait_queue_entry从wait_queue_head链表移除
finish_wait(&wq_head, &__wq_entry); \
__out: __ret; \
})
函数中的WQ_FLAG_EXCLUSIVE为独占等待属性,若__wait_event的exclusive的值为WQ_FLAG_EXCLUSIVE,则:
1)该wait_queue_entry会被添加到wait_queue_head链表的尾部
2)调用wait_up(或变体)唤醒时,独占等待属性的进程只会被唤醒n个(取决于各变体入参),所有非独占属性的仍会被都唤醒,如下
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) //唤醒1个独占属性进程
#define wake_up_nr(x, nr) __wake_up(x, TASK_NORMAL, nr, NULL) //唤醒nr个独占属性进程
To do:
进程唤醒的实现;