阻塞和非阻塞I/O是设备访问的两种模式,阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作得条件后在进行操作,被挂起的进程进入睡眠状态,被从调度器的运行队列移走,直到等待的条件被满足。设备驱动中阻塞I/O一般基于等待队列或基于等待队列的内核API实现。
非阻塞操作的进程在不能进行设备操作时,并不会被挂起,它要么放弃,要么不停的查询直到可以进行操作为止。
非阻塞I/O的应用程序可以借助轮询函数来查询设备是否能被立即访问,在用户程序中,通常使用select(),poll(),epoll()接口查询是否可以对设备进行无阻塞的访问。select(),poll(),epoll()系统调用最终会使设备驱动中的poll()函数被执行。epoll()可以理解为扩展的poll(),当多路复用的文件数量庞大,I/O流量频繁的时候,不太适用select()和poll(),这种情况下,select()和poll()的性能表现较差。这是建议使用epoll(),epoll最大的好处是不会随着fd的数目增长而降低效率。注意设备驱动中的poll()函数本身不会阻塞,与select(),poll(),epoll()相关的系统调用会阻塞的等待至少一个文件描述符集合可被访问或超时。
驱动程序中的poll实现:
__poll_t (*poll) (struct file *, struct poll_table_struct *);
① 对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列头部添加到poll_table中,poll_wait()函数只是把当前进程添加到p