epoll源码剖析
来源:互联网 发布:我的世界商店js 编辑:程序博客网 时间:2024/06/12 22:57
前提:Linux内核源码:linux-2.6.11.12
epoll是一个module,它的底层主要是通过一个文件统“eventpolls”来实现的;epoll的过程是通过三个函数来实现的:epoll_create()、epoll_ctl()、epoll_wait();
相关底层比较重要的结构体有struct eventpoll、struct epitem、struct epollentry、struct __wait_queue;
epoll_create()
epoll_create的底层是通过调用sys_epoll_create,这个系统调用实现的,这里是创建了一个文件系统(eventpoll),并把里面相关的节点关联起来(task_struct 、struct file_struct 、struct file 、struct dentry、struct inode 、struct eventpoll);
下面我们来进入到sys_epoll_create这个函数:
asmlinkage long sys_epoll_create(int size){ int error, fd; struct inode *inode; struct file *file; DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", current, size)); /* Sanity check on the size parameter */ error = -EINVAL; if (size <= 0) goto eexit_1; /* * Creates all the items needed to setup an eventpoll file. That is, * a file structure, and inode and a free file descriptor. */ error = ep_getfd(&fd, &inode, &file); if (error) goto eexit_1; /* Setup the file internal data structure ( "struct eventpoll" ) */ error = ep_file_init(file); if (error) goto eexit_2; DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", current, size, fd)); return fd;eexit_2: sys_close(fd);eexit_1: DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", current, size, error)); return error;}
<1>首先进入函数我们是进行了一系列的参数检查;
<2>接下来,ep_getfd(&fd, &inode, &file),这个函数它主要的作用是分配了fd,inode,file;节选ep_getfd中的重要函数:
file = get_empty_filp();/*pipefs文件系统中的管道分配一个索引节点 对象并对其进行初始化。*/inode = ep_eventpoll_inode();//获取一个inode节点并对其进行初始化error = get_unused_fd();//查找一个文件描述符dentry = d_alloc(eventpoll_mnt->mnt_sb->s_root, &this);//分配一个struct dentry结构;d_add(dentry, inode);//让struct dentry结构中的inode*指针指向inode节点;fd_install(fd, file);//让files_struct里面的fd对应的下标为fd的成员指向file节点;
<3>函数ep_file_init(file),是分配和初始化了一个eventpoll节点,最后让file结构中的private_data指向这个eventpoll,让他们链接起来;
epoll_ctl()
epoll_ctl的底层实现是通过sys_epoll_ctl,它的作用主要是添加新的描述符,或者删除描述符,或者修改描述符所关心的事件;
这个系统调用实现的;以下为sys_poll_ctl中节选部分:
asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event){file = fget(epfd);//通过epfd找到对应的文件对象的地址;tfile = fget(fd);//通过fd找到对应的文件对象的地址;ep = file->private_data;//获取file指向的eventpoll;epi = ep_find(ep, tfile, fd);//在红黑树中查找有没有一个节点中的ffd中保存着tfile和fd,找到返回ffd所对应的epi,如果没有找到,就返回NULL;switch (op) { case EPOLL_CTL_ADD://添加 error = ep_insert(ep, &epds, tfile, fd);break; case EPOLL_CTL_DEL://删除 error = ep_remove(ep, epi);break; case EPOLL_CTL_MOD://修改关心的事件 error = ep_modify(ep, epi, &epds);break; }}
其中比较重要的函数为ep_insert,那么我们就分析一下ep_insert:
struct epitem *epi;init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);revents = tfile->f_op->poll(tfile, &epq.pt);//执行回调函数ep_ptable_queue_proc;ep_rbtree_insert(ep, epi);//添加当前的文件到红黑树中;
ep_ptable_queue_proc()回调函数的作用:这个函数是在f_op->poll时被调用,该函数分配一个等待队列节点epoll_entry,它的作用是:1、把它挂载到文件系统的等待队列中;2、把它挂到epitem等待队列中;3、它还注册了一个等待队列的回调函数;
ep_poll_callback(),回调函数ep_poll_callback函数的作用:当文件操作完成,唤醒当前进程之前,会调用ep_poll_callback,把eventpoll放到epitem的完成队列中;
epoll_wait()
epoll_wait的底层实现是系统调用sys_epoll_wait,它的作用主要是等待文件操作完成并返回;
它的主体是ep_poll,该函数在for循环中,检查epitem上有没有事件就绪,如果有那么就返回,如果没有就调用schedule_timeout进入休眠,知道进程被再次唤醒;
asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, int maxevents, int timeout){ error = ep_poll(ep, events, maxevents, timeout);}
static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, int maxevents, long timeout){ for (;;) { if (!list_empty(&ep->rdllist) || !jtimeout) break; jtimeout = schedule_timeout(jtimeout); }}
epoll性能优点:
epoll机制是通过select/poll的缺陷设计的,epoll是通过一个eventpolls文件系统,将为每个用户生成的fd直接拷贝到内核,不像select每次都得重新拷贝用户的描述符到内核;通过把操作拆分成epoll_create,epoll_ctl,epoll_wait三个函数来实现,避免了这个重复拷贝的过程;我们为每一个描述符所对应的等待队列节点,都设置了回调函数,只要有事件发生,那么由驱动程序去给我调用这个回调函数,将产生就绪事件的节点插入到rdlist,就绪事件链表中,这样的话,我们就可以以O(1)的方式,直接找到就绪事件,并返回给用户;
- epoll源码剖析
- epoll源码剖析
- epoll源码剖析
- epoll源码剖析
- epoll源码剖析
- poll与epoll源码剖析
- 【Linux深入】epoll源码剖析
- 源码剖析之epoll(1)
- 源码剖析之epoll(2)
- select、epoll源码剖析与对比
- epoll剖析
- Linux I/O复用 —— epoll部分源码剖析
- 源码剖析Linux epoll实现机制及Linux上惊群
- epoll和poll剖析
- epoll内核源代码剖析
- epoll原理剖析
- POLL/EPOLL的实现剖析
- epoll LT/ET 深入剖析
- Head First Java#8_多态抽象接口
- 面向对象 8-2
- 【python】如何在某.py文件中调用其他.py内的函数
- 算法导论 最小生成树 MST-PRIM
- Scanern中的nextLine()和next()
- epoll源码剖析
- 2017.08.02回顾 centos安装anaconda/xgboost linux操作系统信息 top内存CPU notebook注释 feature多
- 超简单理解Android四大组件
- LIS-最长递增子序列的长度-java
- 设计模式之类对象结构型 — BRIDGE (桥接)模式
- Jmeter-BeanShell的使用介绍
- MOOC清华《程序设计基础》第8章:二进制文件的数据存取
- 读取word
- 基于UDP的C/S多播回射服务器