为了支持应用层的 select 系统调用,驱动需要实现 poll 方法。标准实现如下:
unsigned int scull_p_poll(struct file *filp, poll_table *wait)
{
}
很简单的代码,问题是怎么实现 select 的读/写查询的?除非可读或写或超时,select 是阻塞的,但是我们这个 poll 方法阻塞在哪里呢?如果阻塞在 poll_wait,那假如第1个(读)poll_wait 阻塞了,第2个(写)poll_wait 得不到调用,此时有空间可写 select 函数也无法知晓;如果是阻塞在外面,poll_wait 只是一个登记的作用,那将来 select 怎么区分最终到底是可读还是可写呢?毕竟 poll_wait 操纵的是同一张表。
其实,阻塞位于 linux-2.4.x/fs/select.c 的 do_select() 函数,大概顺序是:
1:初始化 poll_table 这张表
2:然后依次调用每个文件的 poll 方法
3:poll 方法调用的 poll_wait() 里会调用 init_waitqueue_entry() 和 add_wait_queue(),把当前的进程挂到驱动提供的wait_queue_head_t中
3:假如能读或能写或有信号,就返回
4:调用 schedule_timeout 睡眠
5:当前进程醒来满足:超时,有信号(TASK_INTERRUPTIBLE),驱动唤醒(wake_up_interruptible)
6:继续步骤2,注意反复调用 poll 方法,不会造成 poll_table 的重复插入,因为以后调用 poll 方法的 poll_table 参数为空,此时系统实际上只要获得 mask 来判断到底是可读还是可写