设备驱动之一 - 手工休眠

进程休眠步骤可通过手工设置:
1. 创建和初始化一个等待队列。常由宏定义完成:
 DEFINE_WAIT(my_wait);
    其中的name 是等待队列入口项的名字. 当然也可以用2步来做:
 wait_queue_t my_wait;
 init_wait(&my_wait);
    常用的做法是放一个 DEFINE_WAIT 在循环的顶部,来实现休眠。
2. 添加等待队列入口到队列,并设置进程状态:
 void prepare_to_wait(wait_queue_head_t *queue,
                        wait_queue_t *wait,
                        int state);
    queue 和 wait 分别地是等待队列头和进程入口。
    state 是进程的新状态:TASK_INTERRUPTIBLE(可中断休眠,推荐)或TASK_UNINTERRUPTIBLE(不可中断休眠,不推荐)
3. 在检查确认仍然需要休眠之后调用 schedule
 if (!condition)
      schedule( );    /*调用调度器,并让出CPU*/
4. 清理,schedule 返回,就到了清理时间:
 void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait);
    其实wait_event(queue, condition) 和 wait_event_interruptible(queue, condition) 底层源码也只是手工休眠中的函数的组合。
    所以怕麻烦的话还是用wait_event比较好。
linux设备驱动中的实例:

static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
{
    while (spacefree(dev) == 0) { /* 判断缓冲区是否为NULL */
	/* 创建和初始化一个等待队列 */
        DEFINE_WAIT(wait);

        up(&dev->sem);
        if (filp->f_flags & O_NONBLOCK)
            return -EAGAIN;
        PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
	/* 添加等待队列入口到队列,并设置进程状态TASK_INTERRUPTIBLE */
        prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE); 
	/* 在检查确认仍然需要休眠之后调用 schedule */
        if (spacefree(dev) == 0)
            schedule();	
	/* 执行清理操作 */
        finish_wait(&dev->outq, &wait);
        if (signal_pending(current))
            return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
        if (down_interruptible(&dev->sem))
            return -ERESTARTSYS;
    }
    return 0;
}

posted on 2012-07-26 22:24  YoungerChina  阅读(203)  评论(0编辑  收藏  举报

导航