文章目录
- [一、Linux 内核等待队列(Wait Queue)机制深度分析](#一、Linux 内核等待队列(Wait Queue)机制深度分析)
-
- 1.结构体定义
- 2.宏定义和初始化
- 3.`is_sync_wait`宏定义
- 4.等待队列操作函数
-
- [4.1. `add_wait_queue` - 添加普通等待项](#4.1.
add_wait_queue
- 添加普通等待项) - [4.2 `add_wait_queue_exclusive` - 添加独占等待项](#4.2
add_wait_queue_exclusive
- 添加独占等待项) - [4.3 `remove_wait_queue` - 移除等待项](#4.3
remove_wait_queue
- 移除等待项) - [4.4.`__add_wait_queue` - 头部添加](#4.4.
__add_wait_queue
- 头部添加) - [4.5.`__add_wait_queue_tail` - 尾部添加](#4.5.
__add_wait_queue_tail
- 尾部添加) - [4.6.`__remove_wait_queue` - 移除项](#4.6.
__remove_wait_queue
- 移除项)
- [4.1. `add_wait_queue` - 添加普通等待项](#4.1.
- 5.唤醒相关函数
-
- [5.1.核心唤醒函数 `__wake_up_common`](#5.1.核心唤醒函数
__wake_up_common
) - [5.2. `__wake_up` - 标准唤醒函数](#5.2.
__wake_up
- 标准唤醒函数) - [5.3.`__wake_up_locked` - 已加锁情况下的唤醒](#5.3.
__wake_up_locked
- 已加锁情况下的唤醒) - [5.4. `__wake_up_sync` - 同步唤醒函数](#5.4.
__wake_up_sync
- 同步唤醒函数) - 5.5.普通唤醒宏
- 5.6.数量控制的唤醒宏
- 5.7.全部唤醒宏
- 5.8.可中断唤醒宏
- 5.9.同步唤醒宏
- [5.1.核心唤醒函数 `__wake_up_common`](#5.1.核心唤醒函数
- 6.扩展-`default_wake_function`函数实现
- 7.`wait_event`等待事件宏
-
- 7.1.自动移除唤醒函数`autoremove_wake_function`
- 7.2.定义等待队列项宏`DEFINE_WAIT`
- [7.3. 准备等待函数`prepare_to_wait`](#7.3. 准备等待函数
prepare_to_wait
) - [7.4. 完成等待函数`finish_wait`](#7.4. 完成等待函数
finish_wait
) - [7.5. 内部等待事件宏`__wait_event`](#7.5. 内部等待事件宏
__wait_event
) - [7.6. 最终等待事件宏`wait_event`](#7.6. 最终等待事件宏
wait_event
) - 7.7.完整的工作流程
- 7.8.使用示例
- 7.9.总结
一、Linux 内核等待队列(Wait Queue)机制深度分析
等待队列是 Linux 内核中实现进程同步和等待的重要机制,广泛应用于设备驱动、文件系统和进程调度等领域
1.结构体定义
c
/* 源码文件:include/linux/wait.h */
typedef struct __wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int sync, void *key);
int default_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
struct __wait_queue {
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
struct task_struct * task;
wait_queue_func_t func;
struct list_head task_list;
};
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
1.1.wait_queue_t
和wait_queue_head_t
定义
flags
- 标志位字段
c
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
作用:控制等待队列项的行为特性
当前定义的标志:
WQ_FLAG_EXCLUSIVE
(0x01):独占等待标志- 设置后表示这是一个独占等待者
- 唤醒时只有一个独占等待者会被唤醒(避免"惊群效应")
- 用于资源竞争场景,确保只有一个进程获得资源
task
- 关联的进程描述符
c
struct task_struct * task;
func
- 唤醒回调函数
c
wait_queue_func_t func;
函数类型定义:
c
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int sync, void *key);
作用:当等待条件满足时被调用的函数
task_list
- 链表节点
c
struct list_head task_list;
作用:将等待队列项链接到等待队列中
链表结构定义:
struct list_head {
struct list_head *next, *prev;
};
实际链表结构:
text
wait_queue_head_t (队列头) wait_queue_t A wait_queue_t B wait_queue_t C
↓ ↓ ↓ ↓
task_list → task_list → task_list → task_list
关于内核list详细实现可参考博客 https://blog.csdn.net/weixin_51019352/article/details/152038955
2.宏定义和初始化
c
/* 源码文件:include/linux/wait.h */
#define __WAITQUEUE_INITIALIZER(name, tsk) { \
.task = tsk, \
.func = default_wake_function, \
.task_list = { NULL, NULL } }
#define DECLARE_WAITQUEUE(name, tsk) \
wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \
.lock = SPIN_LOCK_UNLOCKED, \
.task_list = { &(name).task_list, &(name).task_list } }
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
static inline void init_waitqueue_head(wait_queue_head_t *q)
{
q->lock = SPIN_LOCK_UNLOCKED;
INIT_LIST_HEAD(&q->task_list);
}
static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
{
q->flags = 0;
q->task = p;
q->func = default_wake_function;
}
static inline void init_waitqueue_func_entry(wait_queue_t *q,
wait_queue_func_t func)
{
q->flags = 0;
q->task = NULL;
q->func = func;
}
static inline int waitqueue_active(wait_queue_head_t *q)
{
return !list_empty(&q->task_list);
}
2.1.等待队列项初始化宏__WAITQUEUE_INITIALIZER
c
#define __WAITQUEUE_INITIALIZER(name, tsk) { \
.task = tsk, \ // 关联的任务结构体
.func = default_wake_function, \ // 默认唤醒函数
.task_list = { NULL, NULL } } // 链表节点初始化
作用:创建等待队列项的初始化器
2.2.声明等待队列项宏DECLARE_WAITQUEUE
c
#define DECLARE_WAITQUEUE(name, tsk) \
wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk) // 声明并初始化等待队列项
作用:声明并初始化一个等待队列项变量
2.3.等待队列头初始化器宏__WAIT_QUEUE_HEAD_INITIALIZER
c
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \
.lock = SPIN_LOCK_UNLOCKED, \ // 自旋锁初始化为未锁状态
.task_list = { &(name).task_list, &(name).task_list } } // 链表头指向自己
作用:创建等待队列头的初始化器
2.4.声明等待队列头宏DECLARE_WAIT_QUEUE_HEAD
c
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name) // 声明并初始化等待队列头
作用:声明并初始化一个等待队列头变量
2.5. 初始化等待队列头函数
c
static inline void init_waitqueue_head(wait_queue_head_t *q)
{
q->lock = SPIN_LOCK_UNLOCKED; // 初始化自旋锁为未锁状态
INIT_LIST_HEAD(&q->task_list); // 初始化链表头(指向自己)
}
作用:动态初始化一个已分配的等待队列头
2.6.初始化等待队列项函数
c
static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
{
q->flags = 0; // 标志位清零(非独占)
q->task = p; // 关联任务结构体
q->func = default_wake_function; // 设置默认唤醒函数
}
作用:用默认配置初始化等待队列项
2.7.初始化带自定义函数的等待队列项init_waitqueue_func_entry
c
static inline void init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func)
{
q->flags = 0; // 标志位清零
q->task = NULL; // 不关联具体任务
q->func = func; // 设置自定义唤醒函数
}
作用:创建用于特殊目的的等待队列项(如自定义唤醒逻辑)
2.8.检查等待队列是否活动waitqueue_active
c
static inline int waitqueue_active(wait_queue_head_t *q)
{
return !list_empty(&q->task_list); // 检查链表是否为空
}
作用:快速检查等待队列中是否有等待者
2.9.使用场景对比
初始化方式 | 适用场景 | 示例 |
---|---|---|
DECLARE_WAITQUEUE |
静态声明等待项 | DECLARE_WAITQUEUE(wait, current) |
DECLARE_WAIT_QUEUE_HEAD |
静态声明队列头 | DECLARE_WAIT_QUEUE_HEAD(my_queue) |
init_waitqueue_head |
动态初始化队列头 | init_waitqueue_head(&dynamic_queue) |
init_waitqueue_entry |
动态初始化等待项 | init_waitqueue_entry(&wait, current) |
3.is_sync_wait
宏定义
c
/* 源码文件:include/linux/wait.h */
#define is_sync_wait(wait) (!(wait) || ((wait)->task))
!(wait)
:如果wait
指针为 NULL((wait)->task)
:如果wait->task
不为 NULL- 没有等待队列项或者有关联的task,表示是同步等待
4.等待队列操作函数
c
/* 源码文件:kernel/wait.c */
void fastcall 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);
}
void fastcall add_wait_queue_exclusive(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_tail(q, wait);
spin_unlock_irqrestore(&q->lock, flags);
}
void fastcall 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);
}
/* 源码文件:include/linux/wait.h */
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
list_add(&new->task_list, &head->task_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);
}
static inline void __remove_wait_queue(wait_queue_head_t *head,
wait_queue_t *old)
{
list_del(&old->task_list);
}
spin_lock_irqsave
和spin_unlock_irqrestore
的使用可参考博客 https://blog.csdn.net/weixin_51019352/article/details/152059679
4.1. add_wait_queue
- 添加普通等待项
c
void fastcall 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); // 恢复中断状态并解锁
}
4.2 add_wait_queue_exclusive
- 添加独占等待项
c
void fastcall add_wait_queue_exclusive(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_tail(q, wait); // 添加到队列尾部(关键区别!)
spin_unlock_irqrestore(&q->lock, flags);
}
4.3 remove_wait_queue
- 移除等待项
c
void fastcall 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);
}
4.4.__add_wait_queue
- 头部添加
c
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
list_add(&new->task_list, &head->task_list);
}
链表操作效果:
text
添加前: head → [A] → [B]
添加后: head → [new] → [A] → [B]
特点: 头插法
4.5.__add_wait_queue_tail
- 尾部添加
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);
}
链表操作效果:
text
添加前: head → [A] → [B]
添加前: head → [A] → [B] → [new]
特点: 尾插法
4.6.__remove_wait_queue
- 移除项
static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)
{
list_del(&old->task_list);
}
链表操作效果:
text
移除前: head → [A] → [old] → [C] → head
移除old后: head → [A] → [C] → head
5.唤醒相关函数
c
/* 源码文件:kernel/sched.c */
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int sync, void *key)
{
struct list_head *tmp, *next;
list_for_each_safe(tmp, next, &q->task_list) {
wait_queue_t *curr;
unsigned flags;
curr = list_entry(tmp, wait_queue_t, task_list);
flags = curr->flags;
if (curr->func(curr, mode, sync, key) &&
(flags & WQ_FLAG_EXCLUSIVE) &&
!--nr_exclusive)
break;
}
}
void fastcall __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);
spin_unlock_irqrestore(&q->lock, flags);
}
void fastcall __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
{
__wake_up_common(q, mode, 1, 0, NULL);
}
void fastcall __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
{
unsigned long flags;
int sync = 1;
if (unlikely(!q))
return;
if (unlikely(!nr_exclusive))
sync = 0;
spin_lock_irqsave(&q->lock, flags);
__wake_up_common(q, mode, nr_exclusive, sync, NULL);
spin_unlock_irqrestore(&q->lock, flags);
}
/* 源码文件:include/linux/wait.h */
#define wake_up(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
#define wake_up_nr(x, nr) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr, NULL)
#define wake_up_all(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0, NULL)
#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_locked(x) __wake_up_locked((x), TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
#define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
5.1.核心唤醒函数 __wake_up_common
c
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int sync, void *key)
q
: 等待队列头指针mode
: 要唤醒的进程状态模式(如 TASK_INTERRUPTIBLE)nr_exclusive
: 最多唤醒的独占等待者数量sync
: 是否同步唤醒(影响调度行为)key
: 唤醒键值,用于条件匹配
安全遍历链表
c
struct list_head *tmp, *next;
list_for_each_safe(tmp, next, &q->task_list) {
tmp, next
: 当前节点和下一个节点的指针list_for_each_safe
: 宏定义,安全地遍历链表(即使当前节点被删除也能继续)&q->task_list
: 从队列头的链表开始遍历
获取等待队列项
c
wait_queue_t *curr;
unsigned flags;
curr = list_entry(tmp, wait_queue_t, task_list);
flags = curr->flags;
curr
: 当前等待队列项指针flags
: 保存当前项的标志位list_entry
: 宏定义,从链表节点指针获取包含它的结构体指针wait_queue_t, task_list
: 结构体类型和链表成员名
唤醒条件和逻辑
c
if (curr->func(curr, mode, sync, key) &&
(flags & WQ_FLAG_EXCLUSIVE) &&
!--nr_exclusive)
break;
第一部分:curr->func(curr, mode, sync, key)
c
// 调用等待项的唤醒函数,返回非0表示唤醒成功
// 典型实现:default_wake_function
int default_wake_function(wait_queue_t *curr, unsigned mode, int sync, void *key)
{
// 检查进程状态是否匹配唤醒模式
// 如果匹配,调用 try_to_wake_up() 唤醒进程
// 返回1表示成功,表示失败
}
第二部分:(flags & WQ_FLAG_EXCLUSIVE)
c
// 检查是否是独占等待项
// WQ_FLAG_EXCLUSIVE = 0x01
// 如果是独占等待,需要限制唤醒数量
第三部分:!--nr_exclusive
c
// 先递减 nr_exclusive,然后检查是否为0
// 等价于:
nr_exclusive = nr_exclusive - 1;
if (nr_exclusive == 0) {
// 已经达到最大独占唤醒数量,退出循环
}
整体逻辑:
c
// 如果满足以下所有条件,就退出循环:
// 1. 唤醒函数执行成功(进程状态匹配且被唤醒)
// 2. 当前项是独占等待项
// 3. 独占唤醒计数器减到0(达到最大唤醒数量)
5.2. __wake_up
- 标准唤醒函数
c
void fastcall __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); // sync=0 异步唤醒
spin_unlock_irqrestore(&q->lock, flags); // 解锁
}
5.3.__wake_up_locked
- 已加锁情况下的唤醒
c
c
void fastcall __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
{
__wake_up_common(q, mode, 1, 0, NULL); // 唤醒1个独占等待者
}
使用场景: 调用者已经持有队列锁的情况
5.4. __wake_up_sync
- 同步唤醒函数
c
void fastcall __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
{
unsigned long flags;
int sync = 1; // 同步唤醒标志
if (unlikely(!q)) // 检查队列指针是否有效
return; // 无效则直接返回
if (unlikely(!nr_exclusive)) // 如果没有独占唤醒限制
sync = 0; // 使用异步唤醒
spin_lock_irqsave(&q->lock, flags);
__wake_up_common(q, mode, nr_exclusive, sync, NULL); // sync可能为1或0
spin_unlock_irqrestore(&q->lock, flags);
}
同步 vs 异步唤醒的区别:
c
// 异步唤醒(sync=0):
// - 立即返回,被唤醒的进程可能会稍后才运行
// - 性能更好,但实时性较差
// 同步唤醒(sync=1):
// - 等待被唤醒的进程真正开始运行后才返回
// - 用于需要严格顺序执行的场景
// - 性能较差,但保证实时性
5.5.普通唤醒宏
c
#define wake_up(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
- 唤醒不可中断和可中断状态的进程
- 最多唤醒1个独占等待者
- 用于通用唤醒场景
5.6.数量控制的唤醒宏
c
#define wake_up_nr(x, nr) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr, NULL)
- 唤醒指定数量的独占等待者
5.7.全部唤醒宏
c
#define wake_up_all(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0, NULL
nr_exclusive=0
表示不限制独占等待者数量- 唤醒队列中所有匹配的等待者
5.8.可中断唤醒宏
c
#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
- 只唤醒处于
TASK_INTERRUPTIBLE
状态的进程 - 这些进程可以被信号中断
5.9.同步唤醒宏
c
#define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
- 只唤醒可中断状态的进程
- 使用同步唤醒方式(等待被唤醒进程运行)
6.扩展-default_wake_function
函数实现
参考博客 https://blog.csdn.net/weixin_51019352/article/details/152241056
7.wait_event
等待事件宏
c
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
int ret = default_wake_function(wait, mode, sync, key);
if (ret)
list_del_init(&wait->task_list);
return ret;
}
#define DEFINE_WAIT(name) \
wait_queue_t name = { \
.task = current, \
.func = autoremove_wake_function, \
.task_list = { .next = &(name).task_list, \
.prev = &(name).task_list, \
}, \
}
void fastcall
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);
if (is_sync_wait(wait))
set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
}
void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
{
unsigned long flags;
__set_current_state(TASK_RUNNING);
if (!list_empty_careful(&wait->task_list)) {
spin_lock_irqsave(&q->lock, flags);
list_del_init(&wait->task_list);
spin_unlock_irqrestore(&q->lock, flags);
}
}
#define __wait_event(wq, condition) \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \
if (condition) \
break; \
schedule(); \
} \
finish_wait(&wq, &__wait); \
} while (0)
#define wait_event(wq, condition) \
do { \
if (condition) \
break; \
__wait_event(wq, condition); \
} while (0)
7.1.自动移除唤醒函数autoremove_wake_function
c
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
// 调用默认的唤醒函数尝试唤醒任务
int ret = default_wake_function(wait, mode, sync, key);
// 如果唤醒成功,从等待队列中自动移除该等待项
if (ret)
list_del_init(&wait->task_list);
return ret;
}
作用:在唤醒任务后自动清理等待队列项,避免手动管理。
7.2.定义等待队列项宏DEFINE_WAIT
c
#define DEFINE_WAIT(name) \
wait_queue_t name = { \
.task = current, \ // 指向当前任务
.func = autoremove_wake_function, \ // 使用自动移除唤醒函数
.task_list = { .next = &(name).task_list, \
.prev = &(name).task_list, \
}, \
}
作用:创建一个初始化好的等待队列项,形成自循环链表。
初始化后的结构:
c
wait_queue_t __wait = {
.task = current, // 指向当前进程
.func = autoremove_wake_function,
.task_list = {
.next = &__wait.task_list, // 指向自己
.prev = &__wait.task_list // 指向自己
}
};
7.3. 准备等待函数prepare_to_wait
c
void fastcall
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);
// 如果是同步等待,设置任务状态
if (is_sync_wait(wait))
set_current_state(state);
// 释放锁
spin_unlock_irqrestore(&q->lock, flags);
}
关键操作:
__add_wait_queue()
: 将等待项加入到等待队列头部set_current_state()
: 设置当前任务为睡眠状态(如TASK_UNINTERRUPTIBLE
)
7.4. 完成等待函数finish_wait
c
void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
{
unsigned long flags;
// 恢复任务为运行状态
__set_current_state(TASK_RUNNING);
// 小心检查并移除等待项
if (!list_empty_careful(&wait->task_list)) {
spin_lock_irqsave(&q->lock, flags);
list_del_init(&wait->task_list);
spin_unlock_irqrestore(&q->lock, flags);
}
}
关键点:
list_empty_careful()
: 安全地检查链表是否为空(检查前后指针)list_del_init()
: 从链表中删除并重新初始化
7.5. 内部等待事件宏__wait_event
c
#define __wait_event(wq, condition) \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \
if (condition) \
break; \
schedule(); \
} \
finish_wait(&wq, &__wait); \
} while (0)
执行流程:
- 定义等待项
__wait
- 无限循环:
- 准备等待(加入队列+设置状态)
- 检查条件是否满足
- 如果满足,跳出循环
- 否则调用调度器让出CPU
- 完成等待(恢复状态+清理队列)
7.6. 最终等待事件宏wait_event
c
#define wait_event(wq, condition) \
do { \
if (condition) \
break; \
__wait_event(wq, condition); \
} while (0)
优化:先检查条件是否已经满足,避免不必要的等待。
7.7.完整的工作流程
等待端(消费者)
c
wait_event(wq, condition);
- 初始化:创建等待项,指向当前任务
- 准备等待:加入等待队列,设置任务状态
- 循环检查:检查条件,不满足则调度出去
- 唤醒后:条件满足,清理等待队列,恢复运行状态
唤醒端(生产者)
c
// 当条件满足时:
wake_up(&wq);
- 遍历等待队列
- 调用每个等待项的
func
(即autoremove_wake_function
) autoremove_wake_function
调用default_wake_function
唤醒任务- 唤醒成功后自动从队列中移除该等待项
7.7.1.状态机管理
text
TASK_RUNNING → prepare_to_wait → TASK_UNINTERRUPTIBLE
↓
schedule() → 让出CPU
↓
被唤醒 → finish_wait → TASK_RUNNING
7.8.使用示例
c
// 生产者
void producer(void)
{
// ... 生产数据
data_ready = 1;
wake_up(&wq); // 唤醒所有等待者
}
// 消费者
void consumer(void)
{
wait_event(wq, data_ready); // 等待数据就绪
// ... 消费数据
}
7.9.总结
wait_event
宏的实现提供了一个安全、高效的睡眠/唤醒机制:
-
DEFINE_WAIT:创建自动清理的等待项
-
prepare_to_wait:原子性地加入队列+设置状态
-
条件检查循环:防止唤醒丢失
-
schedule:让出CPU,进入睡眠
-
finish_wait:清理状态和队列项
-
autoremove_wake_function:唤醒时自动清理
-
准备等待:加入等待队列,设置任务状态
-
循环检查:检查条件,不满足则调度出去
-
唤醒后:条件满足,清理等待队列,恢复运行状态