进程休眠步骤可通过手工设置:
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; }