手写代码-epoll的内核实现
一、内核实现基础
和之前的select相比,epoll是一个目标性更强的实现。在epoll等待的时候,它会把每个poll的唤醒函数注册为自己特有的函数,在该回调函数中,它将自己(被唤醒的fd)添加到readylist中,然后在poll到底是什么事件的时候只检测在readylist中的描述符即可,而不是像select一样遍历所有的描述符集合进行遍历。大致原理即是如此
二、代码中实现简单说明
这里最为莫名其妙的就是这个ep_reinject_items,把事件返回给用户态之后,此时它会把所有的已经发送的事件再次放入readylist,此时是不是不太符合常规呢?而这一点也是之前比较让我费解的一个地方。
【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)


三、为什么再次注入
这个要和最开始说的epoll实现来看。对于select来说,它每次执行的时候都会进行一次遍历,这样假设说select返回之后,用户态对这个事件充耳不闻,或者其它异常情况没有处理这个事件,那么没关系,再次进入select的时候内核不辞劳苦的又poll了一遍,如果没有处理,状态依然存在。 而对于epoll来说,它的此次状态变化事件执行机会在于事件发生的时候,如果epoll只是简单的将事件发送给用户态之后就从ready队列中删除该项,如果用户态没有处理该event事件,那么再次执行epoll_wait的时候将会丢失这次事件,直到有下一个事件发生并再次执行唤醒检查时才会唤醒用户态进程。这也是和select优化的代价。
四、再次进入内核wait
五、文件等待队列
和select的等待队列每次进入时创建并添加不同,epoll的等待事件创建之后一直不会被删除,直到epoll_create返回的主文件被删除
或者epoll_ctl中EPOLL_CTL_DEL命令删除该关注项。
六、TODO
内核调试态验证以上描述。
