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、只会把该进程往文件的等待队列中加一次