epoll_creat( )
-
在内核注册文件系统eventpollfs,挂载此文件系统
/*
linux一切皆文件,便于处理
若返回指针,指针如果出错则无法判断,而fd可以通过current -> files -> fd_array[ ]找到其真伪
epoll_creat为什么返回一个fd?因为它对应的就是这个文件系统中创建的新文件
*/ -
创建两个内核cache(频繁分配小块内存,应该创建kmem_cahe来做内存池),分别存放struct epitem(事件信息) 和eppoll_entry(用于挂在设备等待队列下)
创建struct eventpoll(红黑树根/就绪链表)结构,放入file -> private data
/*
一个新创建的epoll文件带有一个struct eventpoll结构,这个结构上再挂一个红黑树,而这个红黑树就是每次epoll_ctl 时 fd 存放的地方
*/
epoll_ctl( ) -
检测红黑树中有没有当前fd 有则返回,没有则插入树中:
ep_insert( )
创建struct eppoll_entry(为了放入设备等待队列)
设置其唤醒回调函数为ep_poll_callback
加入设备等待队列 (设备驱动)
(当设备就绪,唤醒等待队列上的等待者时,ep_poll_callback就会被调用,将epitem放入rdlist,每次调用epoll_wait就只收集rdlist里的fd就可以了)
ET/LT 模式
把rdlist里的fd挪到txlist(挪完后rdlist就空了)
epoll_wait( )
| 睡眠 & 检查rdlist是否为空
– ep_poll( )
| 接着把txlist里的fd拷给用户空间,然后ep_reinject_items把一部分fd从txlist里返还给rdlist以便下次还能从rdlist中发现它
– ep_reinject_items( )
将txlist中 没有标注EPOLLET且事件被关注的fd重新放回rdlist,下一次epoll_wait( )会再次响应
Q:Epoll的ET/LT模式在实现上有什么区别?内核上两种模式是如何实现的?
LT模式:当socket缓冲区可读 / 可写时,提醒应用程序处理,若数据未一次处理完成,则会反复提醒。
ET模式:当socket缓冲区可读 / 可写时,只提醒应用程序一次,应用程序必须一次处理完所有数据,直到返回 EAGAIN,否则就会丢失数据。
内核实现:
调用epoll_wait( )后,循环检测rdlist是否为空,当rdlist中有就绪的fd时,将fd复制到txlist(清空rdlist),然后再从txlist复制到用户空间,应用程序得到epoll_wait( )返回后处理数据;若应用程序一次未处理完所有的就绪的fd,在LT模式下,未处理的fd将会被放回rdlist( )调用时返回;而ET模式下,这些未处理的fd将被忽略;