引入poll
相对于select来说,poll 也是在指定时间内论询一定数量的文件描述符,来测试其中是否有就绪的;比起select来,poll代码少,也方便。使用方式的区别也并不大。但是比select要灵活。
poll是一个系统调用,其内核入口函数为sys_poll,sys_poll几乎不做任何处理直接调用do_sys_poll,do_sys_poll的执行过程可以分为三个部分:
1,将用户传入的pollfd数组拷贝到内核空间,因为拷贝操作和数组长度相关,时间上这是一个O(n)操作,这一步的代码在do_sys_poll中包括从函数开始到调用do_poll前的部分。
2,查询每个文件描述符对应设备的状态,如果该设备尚未就绪,则在该设备的等待队列中加入一项并继续查询下一设备的状态。查询完所有设备后如果没有一个设备就绪,这时则需要挂起当前进程等待,直到设备就绪或者超时,挂起操作是通过调用schedule_timeout执行的。设备就绪后进程被通知继续运行,这时再次遍历所有设备,以查找就绪设备。这一步因为两次遍历所有设备,时间复杂度也是O(n),这里面不包括等待时间。相关代码在do_poll函数中。
3,将获得的数据传送到用户空间并执行释放内存和剥离等待队列等善后工作,向用户空间拷贝数据与剥离等待队列等操作的的时间复杂度同样是O(n),具体代码包括do_sys_poll函数中调用do_poll后到结束的部分。
poll函数
头文件包含:#include <poll.h>
函数原型:int poll(struct pollfd fds, nfds_t nfds, int timeout);
struct pollfd 定义为:
struct pollfd {
int fd; / file descriptor /
short events; / requested events /
short revents; / returned events */
};
1.fd 为文件描述符,events 告诉poll 监听fd 上哪些事件,它是一系列事件按位或。revents 由内核修改,来通知应用程序fd 上实际上发生了哪些事件。
在《unix环境高级编程》中有一张events取值的表,如下:
POLLIN :可读除高优级外的数据,不阻塞
POLLRDNORM:可读普通数据,不阻塞
POLLRDBAND:可读O优先数据,不阻塞
POLLPRI:可读高优先数据,不阻塞
POLLOUT :可写普数据,不阻塞
POLLWRNORM:与POLLOUT相同
POLLWRBAND:写非0优先数据,不阻塞
其次revents还有下面取值
POLLERR :已出错
POLLHUP:已挂起,当以描述符被挂起后,就不能再写向该描述符,但是仍可以从该描述符读取到数据。
POLLNVAL:此描述符并不引用一打开文件
2.nfds 为要监视的描述符的数目。
3.timeout 为poll的超时时间,单位毫秒。timeout 为-1时,poll永远阻塞,直到有事件发生。timeout为0时,poll立即返回。
返回值:
返回值>0,表示已侦听到events指定的事件或者出错返回给revents;
返回值=0,表示timeout时间到或者出错返回给revents;
返回值<0,也就是-1,表示出错。