内核对轮询IO(阻塞/非阻塞)的实现
应用层对设备文件的读写,常常会用到轮询操作。所谓轮询,就是指的是在读写时,若暂时无法读写,则卡在那里,直到可以读写。
在应用层,轮询主要分为三种实现
- 纯粹的阻塞式(block)访问
- 循环非阻塞式(nonblock)访问
- 轮询接口(poll)
1.纯粹的阻塞式(block)访问
这种方法的本质是:若读写条件不满足时,则让进程休眠,直到满足条件后由其他进程唤醒(一般是外界触发中断,因为硬件资源获得的同时往往伴随着一个中断),然后进行读写。其实阻塞IO的实现有一点异步通知的思想
- 应用层使用阻塞式(block)访问很简单,默认情况下,open函数的flag就是阻塞的
fd = open("/dev/xxx", O_RDWR);
...
ret = read(fd,&buf,1); /*阻塞式(block)读取*/
- 但是在驱动层,具体的阻塞式(block)操作,比如阻塞读、阻塞写,必须由我们自己实现。内核中通常使用等待队列(wait queue)来实现进程的睡眠/唤醒
- 首先,等待队列在使用前,需要定义与初始化
等待队列一般是全局变量,被定义在驱动程序中device的结构体中
wait_queue_head_t read_waitq;
而初始化一般放在驱动的open/probe函数中,如果没有open/probe的话可以放在module init 的函数中
init_waitqueue_head(read_waitq);
- 接下来就是正式使用了
static ssize_t xxx_read(struct file *file, const char *buffer, size_t count, loff_t *ppos