等待隊列
- wake_up() 可喚醒處于 TASK_INTERRUPTIBLE 和 TASK_UNINTERRUPTIBLE 的程序; wake_up_interruptible() 隻能喚醒處于 TASK_INTERRUPTIBLE 的程序
static ssize_t xx_write(struct file *filp,
const char __user *buf, size_t size, loff_t *ppos)
{
...
/* initial element in wait queue, priv = current */
DECLARE_WAITQUEUE(wait, current);
/* insert element into wait queue */
add_wait_queue(&xxx_wait, &wait);
do {
avail = device_writable(...);
if (avail < ) {
if (filp->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
goto out;
}
set_current_state(TASK_INTERRUPTIBLE);
schedule();
/* be waken up by signal */
if (signal_pending(current)) {
ret = -ERESTARTSYS;
goto out;
}
}
} while(avail < );
device_write(...);
out:
remove_wait_queue(&xxx_wait, &wait);
set_current_state(TASK_RUNNING);
return ret;
}
輪詢
- select(),poll(),epoll() 最終調用驅動中的 poll() 函數
- 多路複用的檔案數量龐大、I/O流量頻繁,一般不适用 select() 和 poll() ,宜用 epoll()
- EPOLLIN 可讀; EPOLLOUT 可寫
- EPOLLET edge triggered, 相對于預設的level triggered, 當fd從未就緒變為就緒時,核心通過epoll告訴使用者,并且不會為該fd繼續發送更多就緒通知
- 驅動程式中 poll() 應完成兩項任務:
- 調用 poll_wait() 将等待隊列頭部添加到 poll_table 中
- 傳回表示能對裝置進行無阻塞讀寫的掩碼
- poll_wait() 本身并不引起阻塞,隻是将等待隊列頭部添加到 poll_table 中,是讓喚醒等待隊列可以喚醒因 select() 而睡眠的程序
static unsigned int xxx_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = ;
struct xxx_dev *dev = flip->private_data;
poll_wait(filp, dev->r_wait, wait);
poll_wait(filp, dev->w_wait, wait);
if (...)
mask |= POLLIN | POLLRDNORM;
if (...)
mask |= POLLOUT | POLLWRNORM;
return mask;
}