等待队列(wait_queue)表示一组睡眠的进程, 当某种条件为真的时候, 由内核来唤醒它们.
等待队列由双向链表来实现, 每一个等待队列都有一个等待队列头(wait_queue_head).
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
由于等待队列经常由中断处理和其他的内核函数来修改所以要对其数据进行保护所以此处使用了spin_lock.
wait_queue_t:
struct __wait_queue {
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
通过DEFINE_WAIT或者DECLARE_WAIT_QUEUE_HEAD来定义一个等待队列
#define DEFINE_WAIT(name) \
wait_queue_t name = { \
.private = current, \
.func = autoremove_wake_function, \
.task_list = LIST_HEAD_INIT((name).task_list), \
}
/* DECLARE_WAIT_QUEUE */
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \
.lock = __SPIN_LOCK_UNLOCKED(name.lock), \
.task_list = { &(name).task_list, &(name).task_list } }
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
DECLARE_WAIT_QUEUE_HEAD创建一个变量然后初始化自旋锁和task_list.
DEFINE_WAIT用cpu上正在运行的进程(current)和autoremove_wake_function初始化该wait_queue_t变量, autoremove_wake_function实际调用default_wake_function()来唤醒睡眠的进程, 然后从wait_queue删除指定元素
default_wake_function实际调用了try_to_wake_up函数.
int default_wake_function(wait_queue_t *curr, unsigned mode, int sync,
void *key)
{
return try_to_wake_up(curr->private, mode, sync);
}
一旦定义了一个元素,就必须把他插入等待队列使用add_wait_queue()函数:
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);
}
该函数把一个非互斥进程插入等待队列中第一个位置,先将等待队列中的flags保证为非互斥进程:wait->flags&=~WQ_FLAG_EXCLUSIVE;然后获取一个自旋锁并且保存中断状态, 使用__add_wait_queue函数将该进程插入等待队列, 最后释放该锁, 恢复中断状态.
__add_wait_queue函数(插入等待队列中第一个位置):
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
list_add(&new->task_list, &head->task_list);
}
add_wait_queue_exclusive和add_wait_queue类似不过不同的是wait->flags |= WQ_FLAG_EXCLUSIVE, 并且互斥进程调用__add_wait_queue_tail将互斥进程插入等待队列的尾部.
如果要等待特定条件的进程可以调用如下列表的函数:
- sleep_on
- interruptible_sleep_on
- sleep_on_timeout
- prepare_to_wait(), prepare_to_wait_exclusive(), finish_wait()
- wait_event