epoll源码剖析

来源:互联网 发布:java质数判断算法 编辑:程序博客网 时间:2024/06/06 10:55

asmlinkage long sys_epoll_create(int size)

功能概要:
1、在执行sys_epoll_create之前会有个初始化工作,它挂在了一个文件系统“eventpollfs”,然后create就是在这个文件系统下分配一个fd给用户
该函数构造相应的数据结构,file,inode,以及分配fd
2、开辟一个eventpoll结构,并且将fd对应的file->private_data指向它
eventpoll结构体定义:
struct eventpoll {/* Protect the this structure access */rwlock_t lock;/* * This semaphore is used to ensure that files are not removed * while epoll is using them. This is read-held during the event * collection loop and it is write-held during the file cleanup * path, the epoll file exit code and the ctl operations. */struct rw_semaphore sem;/* Wait queue used by sys_epoll_wait() */wait_queue_head_t wq;/* Wait queue used by file->poll() */wait_queue_head_t poll_wait;/* List of ready file descriptors */struct list_head rdllist;/* RB-Tree root used to store monitored fd structs */struct rb_root rbr;};
这个结构里面有就绪fd对应的epitem链表,这个结构的等待队列(所有调用epoll_wait的进程的等待队列),用于所有fd对应的epitem对应的连接的红黑树的根

asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)

功能概要:
1、将根据epfd获取到创建时的eventpoll结构,然后在此结构中红黑树种查找这个fd对应的节点是否存在,存在又是插入操作就直接返回,否则根据op选择相应的函数,如果为ADD就调用ep_insert()
2、当然还有将用户空间的传进来的事件拷贝进内核(第一次不可避免,以后就不需要重复传递)

static int ep_insert(struct eventpoll *ep, struct epoll_event *event, struct file *tfile, int fd)

功能概要:
1、申请一个epitem结构,根据fd,events组装一个epitem插入红黑树中
struct epitem {/* RB-Tree node used to link this structure to the eventpoll rb-tree */struct rb_node rbn;/* List header used to link this structure to the eventpoll ready list */struct list_head rdllink;/* The file descriptor information this item refers to */struct epoll_filefd ffd;/* Number of active wait queue attached to poll operations */int nwait;/* List containing poll wait queues */struct list_head pwqlist;/* The "container" of this item */struct eventpoll *ep;/* The structure that describe the interested events and the source fd */struct epoll_event event;/* * Used to keep track of the usage count of the structure. This avoids * that the structure will desappear from underneath our processing. */atomic_t usecnt;/* List header used to link this item to the "struct file" items list */struct list_head fllink;/* List header used to link the item to the transfer list */struct list_head txlink;/* * This is used during the collection/transfer of events to userspace * to pin items empty events set. */unsigned int revents;};


2、开辟一个ep_pqueue这样一个队列节点,其中的函数指针指向ep_ptable_queue_proc
struct ep_pqueue {poll_table pt;struct epitem *epi;};

3、调用该文件描述符的poll方法,这里第一次仅仅将该进程加入该文件描述符的等待队列中

static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,poll_table *pt)

功能概要:
申请一个ep_pentry结构体:
struct eppoll_entry {/* List header used to link this structure to the "struct epitem" */struct list_head llink;/* The "base" pointer is set to the container "struct epitem" */void *base;/* * Wait queue item that will be linked to the target file wait * queue head. */wait_queue_t wait;/* The wait queue head that linked the "wait" wait queue item */wait_queue_head_t *whead;};
1、这里将base指向epitem,将wait中的的唤醒函数设置为ep_poll_callback,task设置为本进程的PCB,whead设置为该文件的等待队列的头,然后将wait把当前进程通过whead挂入该文件的等该队列,这里加入队列之后就不需要再次调用加入,以后就是通过epoll_wait等待就对了
2、当哪个文件的有事件到达时就调用ep_poll_callback函数,此函数的功能就是将就绪的epitem加入eventpoll中的就绪队列中

asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,    int maxevents, int timeout)

功能概要:
1、扫描rdlist队列中是否为空,为空就睡眠,不为空就从相应的epitem中中file调用poll方法得到掩码复制给revents,并将revents拷贝到用户空间events中,events是一个epoll_event结构体数组指针,将发生事件的所有的fd,相应事件都保存在其中。
2、将epitem从rdlist中通过txlink链接到一个txlist中(传输链表中),比对传输链接中的每一个epitem是否为EPOLLET模式,不是ET模式就将epitem放回rdlist中,否则就从链表中删除

优点:

1、没有最大文件描述符的限制
2、只有第一次才会从用户空间进行拷贝,后面调用不需要重复拷贝,返回结果也是只返回有事件发生的fd,其他不返回,提高了效率
3、只会把该进程往文件的等待队列中加一次