首页 > 代码库 > poll&&epoll实现分析(二)——epoll实现
poll&&epoll实现分析(二)——epoll实现
Epoll实现分析——作者:lvyilong316
通过上一章分析,poll运行效率的两个瓶颈已经找出,现在的问题是怎么改进。首先,如果要监听1000个fd,每次poll都要把1000个fd 拷入内核,太不科学了,内核干嘛不自己保存已经拷入的fd呢?答对了,epoll就是自己保存拷入的fd,它的API就已经说明了这一点——不是 epoll_wait的时候才传入fd,而是通过epoll_ctl把所有fd传入内核再一起"wait",这就省掉了不必要的重复拷贝。其次,在 epoll_wait时,也不是把current轮流的加入fd对应的设备等待队列,而是在设备等待队列醒来时调用一个回调函数(当然,这就需要“唤醒回调”机制),把产生事件的fd归入一个链表,然后返回这个链表上的fd。
另外,epoll机制实现了自己特有的文件系统eventpoll filesystem
1. 内核数据结构
(1) struct eventpoll {
spinlock_t lock;
struct mutex mtx;
wait_queue_head_t wq; /* Wait queue used by sys_epoll_wait() ,调用epoll_wait()时, 我们就是"睡"在了这个等待队列上*/
wait_queue_head_t poll_wait; /* Wait queue used by file->poll() , 这个用于epollfd本事被poll的时候*/
struct list_head rdllist; /* List of ready file descriptors, 所有已经ready的epitem都在这个链表里面*/
structrb_root rbr; /* RB tree root used to store monitored fd structs, 所有要监听的epitem都在这里*/
epitem *ovflist; /*存放的epitem都是我们在传递数据给用户空间时监听到了事件*/.
struct user_struct *user; /*这里保存了一些用户变量,比如fd监听数量的最大值等*/
};
通过epoll_ctl接口加入该epoll描述符监听的套接字则属于socket filesystem,这点一定要注意。每个添加的待监听(这里监听和listen调用不同)都对应于一个epitem结构体,该结构体已红黑树的结构组织,eventpoll结构中保存了树的根节点(rbr成员)。同时有监听事件到来的套接字的该结构以双向链表组织起来,链表头保存在eventpoll中(rdllist成员)。
/*
* Each file descriptor added to the eventpoll interface will have an entry of this type linked to the "rbr" RB tree.
*/
(2) struct epitem {
struct rb_node rbn; /* RB tree node used to link this structure to the eventpoll RB tree */
struct list_head rdllink; /* 链表节点, 所有已经ready的epitem都会被链到eventpoll的rdllist中 */
struct epitem *next;
struct epoll_filefd ffd; /* The file descriptor information this item refers to */
int nwait; /* Number of active wait queue attached to poll operations */
struct list_head pwqlist; /* List containing poll wait queues */
struct eventpoll *ep; /* The "container" of this item */
struct list_head fllink; /* List header used to link this item to the "struct file" items list */
struct epoll_event event; /*当前的epitem关系哪些events, 这个数据是调用epoll_ctl时从用户态传递过来 */
};
(3) struct epoll_filefd {
struct file *file;
int fd;};
(4) struct eppoll_entry { /* Wait structure used by the poll hooks */
struct list_head llink; /* List header used to link this structure to the "struct epitem" */
struct epitem *base; /* The "base" pointer is set to the container "struct epitem" */
wait_queue_t wait; / Wait queue item that will be linked to the target file wait queue head. /
wait_queue_head_t *whead;/The wait queue head that linked the "wait" wait queue item */
};//注:后两项相当于等待队列
(5) struct ep_pqueue {/* Wrapper struct used by poll queueing */
poll_table pt; // struct poll_table是一个函数指针的包裹
struct epitem *epi;
};
(6) struct ep_send_events_data {
/* Used by the ep_send_events() function as callback private data */
int maxevents;
struct epoll_event __user *events;
};