阻塞
设备驱动不阻塞,用户想获取设备资源只能不停的查询,这无谓的消耗CPU资源。而阻塞访问,不能获取资源的进程将进入休眠,它将CPU资源“礼让”给其他进程
唤醒进程的地方最大可能发生在中断里面,因为硬件资源获得的同时往往伴随着一个中断
定义头
wait_queue_head_t queue;
初始化头
#define init_waitqueue_head(q)
定义
#define DECLARE_WAITQUEUE(name, tsk)
添加
extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
移除
extern void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
等待事件
#define wait_event(wq, condition)
#define wait_event_timeout(wq, condition, timeout)
#define wait_event_interruptible(wq, condition)
#define wait_event_interruptible_timeout(wq, condition, timeout)
wq:等待队列
condition:必须满足,否则继续阻塞
interruptible:可以被信号打断
timeout:超时时间。不论condition是否满足,均返回
wait_event
#define wait_event(wq, condition) \
do { \
if (condition) //条件满足立即返回 \
break; \
__wait_event(wq, condition); //添加等待队列,阻塞 \
} while (0)
#define __wait_event(wq, condition) \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \
if (condition) \
break; \
schedule(); //放弃CPU \
} \
finish_wait(&wq, &__wait); \
} while (0)
唤醒
#define wake_up(x)
#define wake_up_interruptible(x)
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_interruptible只能唤醒处于TASK_INTERRUPTIBLE的进程
在等待队列上睡眠
extern void sleep_on(wait_queue_head_t *q);
extern long sleep_on_timeout(wait_queue_head_t *q,
signed long timeout);
extern void interruptible_sleep_on(wait_queue_head_t *q);
extern long interruptible_sleep_on_timeout(wait_queue_head_t *q,
signed long timeout);
一般不用,而是直接进行状态切换
举例
if (mutex_lock_interruptible(&ir->buf_lock))
return -ERESTARTSYS;
DECLARE_WAITQUEUE(wait, current); //定义等待队列
add_wait_queue(&ir->buf.wait_poll, &wait); //添加等待队列
set_current_state(TASK_INTERRUPTIBLE); //改变进程状态
while (written < n)
{
if (lirc_buffer_empty(&ir->buf))
{
if (filep->f_flags & O_NONBLOCK) //非阻塞
{
ret = -EWOULDBLOCK;
break;
}
if (signal_pending(current)) //因信号唤醒
{
ret = -ERESTARTSYS;
break;
}
schedule(); //调度其他进程
set_current_state(TASK_INTERRUPTIBLE);
}
else
{
lirc_buffer_read(&ir->buf, buf);
ret = copy_to_user((void *)outbuf+written, buf,
ir->buf.chunk_size);
written += ir->buf.chunk_size;
}
}
remove_wait_queue(&ir->buf.wait_poll, &wait); //将等待队列移出等待队列头
set_current_state(TASK_RUNNING); //改变进程状态TASK_RUNNING
mutex_unlock(&ir->buf_lock);