等待队列 阻塞非阻塞

阻塞
设备驱动不阻塞,用户想获取设备资源只能不停的查询,这无谓的消耗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);
posted @ 2017-06-01 17:24  thomas_blog  阅读(169)  评论(0编辑  收藏  举报