在Linux驱动程序中,可以使用等待队列(wait queue)来实现阻塞进程的唤醒。wait queue很早就作为一种基本的功能单位出现在Linux内核里了,它以队列位基础数据结构,与进程调度机制紧密结合,能够用于实现内核中异步事件通知机 制。等待队列可以用来同步对系统资源的访问。(信号量在内核中也依赖等待队列来实现)。
Linux-2.6提供如下关于等待队列的操作:
(1) 定义"等待队列头",
wait_queue_head_t my_queue;
defined in linux/wait.h
50 struct __wait_queue_head {
(2) 初始化"等待队列头"
init_waitqueue_head(&my_queue);
defined in linux/wait.c header file
13 void init_waitqueue_head( wait_queue_head_t *q)
定义和初始化的快捷方式:
DECLARE_WAIT_QUEUE_HEAD(my_queue);
linux/wait.h
(3) 定义等待队列
DECLARE_WAITQUEUE(name, tsk);
定义并初始化一个名为name的等待队列(wait_queue_t);
linux/wait.h
(4) 添加/移除等待队列
void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
add_wait_queue()用于将等待队列wait添加到等待队列头q指向的等待队列链表中,而remove_wait_queue()用于将等待队列wait从附属的等待队列头q指向的等待队列链表中移除。
(5) 等待事件
wait_event(queue, condition);
wait_event_interruptible(queue, condition);
wait_event_timeout(queue, condition, timeout);
wait_event_interruptible_timeout(queue, condition, timeout);
等待第一个参数queue作为等待队列头的等待队列被唤醒,而且第二个参数condition必须满足,否则阻塞。wait_event()和 wait_event_interruptible()的区别在于后者可以被信号打断,而前者不能。加上timeout后的宏意味着阻塞等待的超时时间, 以jiffy为单位,在第三个参数的timeout到达时,不论condition是否满足,均返回。
(6) 唤醒队列
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
上述操作会唤醒以queue作为等待队列头的所有等待队列对应的进程。
wake_up() <---> wait_event()
wait_event_timeout()
wake_up_interruptible() <---> wait_event_interruptible()
wait_event_interruptible_timeout()
wake_up()可以唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的进程
wake_up_interruptble()只能唤醒处于TASK_INTERRUPTIBLE的进程。
(7) 在等待队列上睡眠
sleep_on(wait_queue_head_t *q);
interruptible_sleep_on(wait_queue_head_t *q);
sleep_on()函数的作用就是将当前进程的状态置成TASK_UNINTERRUPTIBLE,定义一个等待队列,并把它添加到等待队列头q,直到支援获得,q引导的等待队列被唤醒。
interruptible_sleep_on()与sleep_on()函数类似,其作用是将目前进程的状态置成 TASK_INTERRUPTIBLE,并定义一个等待队列,之后把它附属到等待队列头q,直到资源可获得,q引导的等待队列被唤醒或者进程收到信号。
sleep_on() <---> wake_up()
interruptible_sleep_on() <---> wake_up_interruptible()
Linux-2.6提供如下关于等待队列的操作:
(1) 定义"等待队列头",
wait_queue_head_t my_queue;
defined in linux/wait.h
50 struct __wait_queue_head {
51 spinlock_t lock;
52 struct list_head task_list;
53 };
54 typedef struct __wait_queue_head wait_queue_head_t;
(2) 初始化"等待队列头"
init_waitqueue_head(&my_queue);
defined in linux/wait.c header file
13 void init_waitqueue_head( wait_queue_head_t *q)
14 {
15 spin_lock_init(&q->lock);
16 INIT_LIST_HEAD(&q->task_list);
17 }
定义和初始化的快捷方式:
DECLARE_WAIT_QUEUE_HEAD(my_queue);
linux/wait.h
70 #define __WAIT_QUEUE_HEAD_INITIALIZER(name) { /
71 .lock = __SPIN_LOCK_UNLOCKED(name.lock), /
72 .task_list = { &(name).task_list, &(name).task_list } }
74 #define DECLARE_WAIT_QUEUE_HEAD(name) /
75 wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
(3) 定义等待队列
DECLARE_WAITQUEUE(name, tsk);
定义并初始化一个名为name的等待队列(wait_queue_t);
linux/wait.h
32 struct __wait_queue {
33 unsigned int flags;
34 #define WQ_FLAG_EXCLUSIVE 0x01
35 void *private;
36 wait_queue_func_t func;
37 struct list_head task_list;
38 };
28 typedef struct __wait_queue wait_queue_t;
62 #define __WAITQUEUE_INITIALIZER(name, tsk) { /
63 .private = tsk, /
64 .func = default_wake_function, /
65 .task_list = { NULL, NULL } }
66
67 #define DECLARE_WAITQUEUE(name, tsk) /
68 wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
(4) 添加/移除等待队列
void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
add_wait_queue()用于将等待队列wait添加到等待队列头q指向的等待队列链表中,而remove_wait_queue()用于将等待队列wait从附属的等待队列头q指向的等待队列链表中移除。
(5) 等待事件
wait_event(queue, condition);
wait_event_interruptible(queue, condition);
wait_event_timeout(queue, condition, timeout);
wait_event_interruptible_timeout(queue, condition, timeout);
等待第一个参数queue作为等待队列头的等待队列被唤醒,而且第二个参数condition必须满足,否则阻塞。wait_event()和 wait_event_interruptible()的区别在于后者可以被信号打断,而前者不能。加上timeout后的宏意味着阻塞等待的超时时间, 以jiffy为单位,在第三个参数的timeout到达时,不论condition是否满足,均返回。
(6) 唤醒队列
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
上述操作会唤醒以queue作为等待队列头的所有等待队列对应的进程。
wake_up() <---> wait_event()
wait_event_timeout()
wake_up_interruptible() <---> wait_event_interruptible()
wait_event_interruptible_timeout()
wake_up()可以唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的进程
wake_up_interruptble()只能唤醒处于TASK_INTERRUPTIBLE的进程。
(7) 在等待队列上睡眠
sleep_on(wait_queue_head_t *q);
interruptible_sleep_on(wait_queue_head_t *q);
sleep_on()函数的作用就是将当前进程的状态置成TASK_UNINTERRUPTIBLE,定义一个等待队列,并把它添加到等待队列头q,直到支援获得,q引导的等待队列被唤醒。
interruptible_sleep_on()与sleep_on()函数类似,其作用是将目前进程的状态置成 TASK_INTERRUPTIBLE,并定义一个等待队列,之后把它附属到等待队列头q,直到资源可获得,q引导的等待队列被唤醒或者进程收到信号。
sleep_on() <---> wake_up()
interruptible_sleep_on() <---> wake_up_interruptible()