select/poll/epoll
1、select的实现(fs/select.c)
主要涉及三个函数sys_select() à core_sys_select() à do_select()
每次调用select,都会将用户态的fd拷贝至内核态
do_select()会
1) 循环遍历每一个fd,调用对应的驱动的poll函数,poll函数会:1)将用户进程插入到驱动的等待队列中 2)返回mask告知就绪fd
2) 如果遍历完都没有,for循环进入睡眠,等待被驱动唤醒或超时退出
3) 如果遍历完有可操作的fd,则跳出for循环
2、poll的实现(fs/select.c)
主要涉及三个函数sys_poll()->do_sys_poll()->do_poll()
poll的实现和select非常相似,区别就是入参方式变了,由固定大小的位图改成了变长的指针数组,select中存放文件描述符集合,是用的数组,poll中替换成了链表,这样就没有了1024的限制
3、epoll的实现(fs/eventpoll.c)
epoll机制是通过向驱动注册回调函数的方式获得IO就绪的通知
其使用过程如下:
第一步:epoll_create会创建一个对象, 该对象包含两个数据结构,一个红黑树,一个链表;
第二步:epoll_ctl会将要关注的fd存入红黑树数据结构,当有事件触发时,内核会将就绪的fd拷贝到链表数据结构
第三部:epoll_wait从链表里读取就绪的fd,移到用户空间
注意:epoll_create的入参需要填入一个任意的大于0的int, 该参数已无具体意义
总结:
(1)select支持的文件描述符有1024的限制,poll 没有限制
(2)select和poll实现机制相似,每次调用,都需要把fd集合从用户态拷贝到内核态,然后遍历所有的fd, 再拷贝回用户态
(3)epoll避免了fd在用户态和内核态间的反复拷贝, 其内部的回调机制,以及就绪链表的存在,使得在io数量超多的情况下,其效率比select/poll要高效很多