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_twait_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_irqsavespin_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. 唤醒后:条件满足,清理等待队列,恢复运行状态

相关推荐
wheeldown2 小时前
【Linux】Linux管道与进程池深度解析:从原理到实战
linux·运维·服务器
_extraordinary_3 小时前
Java Linux --- 基本命令,部署Java web程序到线上访问
java·linux·前端
Ronin3053 小时前
【Linux网络】网络命令
linux·网络·网络命令
XUE-52113144 小时前
BGP实验-路由反射器
linux·运维·网络
upgrador4 小时前
Linux内核与设备管理:USB存储驱动usb_storage/uas的安全卸载与复原
linux·运维·安全
风为你而吹5 小时前
【玩泰山派】4、制作ubuntu镜像-(5)总结制作镜像流程
linux·ubuntu
tt5555555555555 小时前
Linux虚拟机固定IP超详细教程
linux·运维·tcp/ip
阑梦清川6 小时前
动静态库和编译链接简述
linux
拾光Ծ6 小时前
【Linux】入门指南:基础指令详解Part One
linux·运维·服务器·centos