struct eventop {
	const char *name;
	void *(*init)(struct event_base *); // 初始化
	int (*add)(void *, struct event *); // 注册事件
	int (*del)(void *, struct event *); // 删除事件
	int (*dispatch)(struct event_base *, void *, struct timeval *); // 事件分发
	void (*dealloc)(struct event_base *, void *); // 注销,释放资源
	/* set if we need to reinitialize the event base */
	int need_reinit;
};在libevent中,每种I/O demultiplex机制的实现都必须提供这五个函数接口,来完成自身的初始化、销毁释放;对事件的注册、注销和分发。比如对于epoll,libevent实现了5个对应的接口函数,并在初始化时并将eventop的5个函数指针指向这5个函数,那么程序就可以使用epoll作为I/O demultiplex机制了。/* In order of preference */
static const struct eventop *eventops[] = {
#ifdef HAVE_EVENT_PORTS
		&evportops,
#endif
#ifdef HAVE_WORKING_KQUEUE
		&kqops,
#endif
#ifdef HAVE_EPOLL
		&epollops,
		35
#endif
#ifdef HAVE_DEVPOLL
		&devpollops,
#endif
#ifdef HAVE_POLL
		&pollops,
#endif
#ifdef HAVE_SELECT
		&selectops,
#endif
#ifdef WIN32
		&win32ops,
#endif
		NULL
};然后libevent根据系统配置和编译选项决定使用哪一种I/O demultiplex机制,这段代码在函数event_base_new()中:	base->evbase = NULL;
for (i = 0; eventops[i] && !base->evbase; i++) {
	base->evsel = eventops[i];
	base->evbase = base->evsel->init(base);
}可以看出,libevent在编译阶段选择系统的I/O demultiplex机制,而不支持在运行阶段根据配置再次选择。	const struct eventop epollops = {
		"epoll",
		epoll_init,
		epoll_add,
		epoll_del,
		epoll_dispatch,
		epoll_dealloc,
		1 /* need reinit */
         };变量epollops中的函数指针具体声明如下,注意到其返回值和参数都和eventop中的定义严格一致,这是函数指针的语法限制。static void *epoll_init (struct event_base *); static int epoll_add (void *, struct event *); static int epoll_del (void *, struct event *); static int epoll_dispatch(struct event_base *, void *, struct timeval *); static void epoll_dealloc (struct event_base *, void *);那么如果选择的是epoll,那么调用结构体eventop的init和dispatch函数指针时,实际调用的函数就是epoll的初始化函数epoll_init()和事件分发函数epoll_dispatch()了;
原文:http://blog.csdn.net/shimazhuge/article/details/45178759