Linux I/O复用 —— epoll部分源码剖析
epoll_creat( )
1. 在内核注册文件系统eventpollfs,挂载此文件系统
2. 创建两个内核cache(频繁分配小块内存,应该创建kmem_cahe来做内存池),分别存放struct epitem(事件信息) 和eppoll_entry(用于挂在设备等待队列下)
创建struct eventpoll(红黑树根/就绪链表)结构,放入file -> private data
epoll_ctl( )
3. 检测红黑树中有没有当前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( )
1. 在内核注册文件系统eventpollfs,挂载此文件系统
/*
linux一切皆文件,便于处理
若返回指针,指针如果出错则无法判断,而fd可以通过current -> files -> fd_array[ ]找到其真伪epoll_creat为什么返回一个fd?因为它对应的就是这个文件系统中创建的新文件
*/
2. 创建两个内核cache(频繁分配小块内存,应该创建kmem_cahe来做内存池),分别存放struct epitem(事件信息) 和eppoll_entry(用于挂在设备等待队列下)
创建struct eventpoll(红黑树根/就绪链表)结构,放入file -> private data
/*
一个新创建的epoll文件带有一个struct eventpoll结构,这个结构上再挂一个红黑树,而这个红黑树就是每次epoll_ctl 时 fd 存放的地方
*/
epoll_ctl( )
3. 检测红黑树中有没有当前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( ) 会再次响应