等待队列主要用于:当任务(进程)由于某个条件得不到满足时,为避免不必要的轮询,使得进程在等待期间进入睡眠状态,直到等待的条件得到满足时由内核唤醒,进入运行状态。
等待队列是基于双循环链表structlist_head来实现的,与进程调度机制紧密结合,能够用于实现核心的异步事件通知机制。
1 数据结构
struct __wait_queue
{
unsigned int flags; /*0:非互斥进程,0x01:互斥进程*/
#define WQ_FLAG_EXCLUSIVE 0x01 /*表示等待进程想要被独占地唤醒*/
void *private; /*指向等待进程的task_struct实例*/
wait_queue_func_t func; /*用于唤醒等待进程*/
struct list_head task_list; /*将wait_queue_t添加到wait_queue_head_t*/
};
typedef struct __wait_queue wait_queue_t;/*等待队列项*/
struct __wait_queue_head
{
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;/*等待队列头*/
Linux等待队列的实现思想:当一个任务(进程)需要在某个等待队列wait_queue_head_t上睡眠时,将自己的进程控制块信息封装到等待队列项wait_queue_t中,然后挂载到wait_queue_head_t的链表中,执行调度睡眠。当等待的某个事件发生后,另一个任务(进程)会唤醒等待队列wait_queue_head_t上的某个任务或所有任务,唤醒工作即是将等待队列中的任务设置为可调度状态,并且从队列中删除。
2 函数
2.1 初始化等待队列
void init_waitqueue_head(wait_queue_head_t *q); |
2.2 等待事件
#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) |
等待事件函数 | 描述 |
wait_event(wq,condition) | 进程状态被设置为 TASK_UNINTERRUPTIBLE,进入睡眠 |
wait_event_interruptible(wq, condition) | 设进程为TASK_INTERRUPTIBLE状态,睡眠期间被信号唤醒则返回-ERESTARTSYS错误码 |
wait_event_interruptible_exclusive(wq, condition) | 睡眠的为互斥进程 |
wait_event_timeout(wq, condition, timeout) | 超时返回0 |
wait_event_interruptible_timeout(wq, condition, timeout) | 睡眠期间被信号唤醒则返回ERESTARTSYS错误码 |
2.3 唤醒等待进程
#define wake_up(x) __wake_up(x, (unsigned int)(TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE), 1, NULL) |
唤醒函数 | 描述 |
wake_up(x) | 可唤醒进程状态为TASK_UNINTERRUPTIBLE和TASK_INTERRUPTIBLE的进程,与wait_event、wait_event_timeout成对使用 |
wake_up_all(x) | 唤醒所有等待的进程 |
wake_up_interruptible(x) | 仅唤醒进程状态为TASK_INTERRUPTIBL的进程,与wait_event_interruptible、wait_event_interruptible_timeout成对使用 |