libevent源码分析--epoll中的几个函数 epoll_init epoll_add epoll_dispatch

这篇文件讲解下上面的几篇文章中欠下的几个函数解释。在看这个之前,请移步这篇文章这里说明了libevent库在编译的时候已经决定了所使用的I/O复用机制,系统中提供了五种机制:在这里指选择一种来说明 epoll

在even-internal.h文件中有一个结构体,

38 struct eventop {
 39     const char *name;
 40     void *(*init)(struct event_base *);
 41     int (*add)(void *, struct event *);
 42     int (*del)(void *, struct event *);
 43     int (*dispatch)(struct event_base *, void *, struct timeval *);
 44     void (*dealloc)(struct event_base *, void *);
 45     /* set if we need to reinitialize the event base */
 46     int need_reinit;
 47 };

这个结构体中的每个字段,都是函数指针,函数指针其实就是C语言中的多态,上面的这五个字段在编译的时候指向某个系统调用中的五个函数。也就是event_base中的evsel指针。在epoll机制中,首先封装了struct event :

59 struct evepoll {
 60     struct event *evread;
 61     struct event *evwrite;
 62 };

接下来又是一个结构体:

64 struct epollop {
 65     struct evepoll *fds;
 66     int nfds;
 67     struct epoll_event *events;
 68     int nevents;
 69     int epfd;
 70 };
然后是五个函数,就是event中需要的五个函数
72 static void *epoll_init (struct event_base *);
 73 static int epoll_add    (void *, struct event *);
 74 static int epoll_del    (void *, struct event *);
 75 static int epoll_dispatch   (struct event_base *, void *, struct timeval *);
 76 static void epoll_dealloc   (struct event_base *, void *);
然后初始化一个结构体, 这个结构体的名字就是epollops

78 const struct eventop epollops = {
 79     "epoll",
 80     epoll_init,
 81     epoll_add,
 82     epoll_del,
 83     epoll_dispatch,
 84     epoll_dealloc,
 85     1 /* need reinit */
 86 };
看在具体的代码中怎么使用上述的内容的:

107 static void *
108 epoll_init(struct event_base *base)
109 {
110     int epfd, nfiles = NEVENT;
111     struct rlimit rl;
112     struct epollop *epollop;
113 
114     /* Disable epollueue when this environment variable is set */
115     if (getenv("EVENT_NOEPOLL"))
116         return (NULL);
117 
118     if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
119         rl.rlim_cur != RLIM_INFINITY) {
120         /*
121          * Solaris is somewhat retarded - it‘s important to drop
122          * backwards compatibility when making changes.  So, don‘t
123          * dare to put rl.rlim_cur here.
124          */
125         nfiles = rl.rlim_cur - 1;
126     }
127 
128     /* Initalize the kernel queue */
129 
130     if ((epfd = epoll_create(nfiles)) == -1) {
131         if (errno != ENOSYS)
132             event_warn("epoll_create");
133         return (NULL);
134     }
135 
136     FD_CLOSEONEXEC(epfd);
137 
138     if (!(epollop = calloc(1, sizeof(struct epollop))))
139         return (NULL);
140 
141     epollop->epfd = epfd;
142 
143     /* Initalize fields */
144     epollop->events = malloc(nfiles * sizeof(struct epoll_event));
145     if (epollop->events == NULL) {
146         free(epollop);
147         return (NULL);
148     }
149     epollop->nevents = nfiles;
150 
151     epollop->fds = calloc(nfiles, sizeof(struct evepoll));
152     if (epollop->fds == NULL) {
153         free(epollop->events);
154         free(epollop);
155         return (NULL);
156     }
157     epollop->nfds = nfiles;
158 
159     evsignal_init(base);
160 
161     return (epollop);
162 }

 在这篇文章中使用了init,其实如果系统在编译中使用的epol机制,最终调用的就是上面的这个函数。

在130行调用了系统调用event_create,生成的32000个套接字描述符,从143行开始初始化,也就是32000个描述符,每个描述符都是一个struct epoll_event,在这个函数体中最终生成的一些列东西都是返回一个struct epollop,也就是上面其中一个结构体的封装。函数最后的返回值也是epollop.下面来看看这个函数式怎么初始化struct epollops的。在130行event_create返回值的epfd最终赋值给了epollop->epfd,而epollop->fds在151行是动态申请可空间,大小也是nfiles=NEVENT = 32000,epollop中的nevents和nfds都是NEVENT.这里暂时不讨论关于信号的任何内容。

这个函数也就是相当于初始化了一个struct epollop.



libevent源码分析--epoll中的几个函数 epoll_init epoll_add epoll_dispatch

上一篇:享元模式-AbstractMap结构


下一篇:Struts前台无乱码传向后台时出现乱码问题的解决办法