Linux 内核等待队列(Wait Queue)机制深度分析

文章目录

一、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)

执行流程:

  1. 定义等待项 __wait
  2. 无限循环:
    • 准备等待(加入队列+设置状态)
    • 检查条件是否满足
    • 如果满足,跳出循环
    • 否则调用调度器让出CPU
  3. 完成等待(恢复状态+清理队列)

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);
  1. 初始化:创建等待项,指向当前任务
  2. 准备等待:加入等待队列,设置任务状态
  3. 循环检查:检查条件,不满足则调度出去
  4. 唤醒后:条件满足,清理等待队列,恢复运行状态

唤醒端(生产者)

c 复制代码
// 当条件满足时:
wake_up(&wq);
  1. 遍历等待队列
  2. 调用每个等待项的 func(即 autoremove_wake_function)
  3. autoremove_wake_function 调用 default_wake_function 唤醒任务
  4. 唤醒成功后自动从队列中移除该等待项
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 宏的实现提供了一个安全、高效的睡眠/唤醒机制:

  1. DEFINE_WAIT:创建自动清理的等待项

  2. prepare_to_wait:原子性地加入队列+设置状态

  3. 条件检查循环:防止唤醒丢失

  4. schedule:让出CPU,进入睡眠

  5. finish_wait:清理状态和队列项

  6. autoremove_wake_function:唤醒时自动清理

  7. 准备等待:加入等待队列,设置任务状态

  8. 循环检查:检查条件,不满足则调度出去

  9. 唤醒后:条件满足,清理等待队列,恢复运行状态

相关推荐
陈希1236 分钟前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
女神下凡40 分钟前
芯参谋(95):嵌入式文件系统_开发指南
linux·服务器·arm开发·驱动开发·设计规范
且从容.4 小时前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道5 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.8 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落9 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨9 小时前
WSL2的安装与使用
linux·wsl
微小的鱼9 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng10 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮10 小时前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频