之前的博文讲了怎么实现线程、锁、内存分配、日志等功能的跨平台。Libevent最重要的跨平台功能还是实现了多路IO接口的跨平台(即Reactor模式)。这使得用户可以在不同的平台使用统一的接口。这篇博文就是来讲解Libevent是怎么实现这一点的。
Libevent在实现线程、内存分配、日志时,都是使用了函数指针和全局变量。在实现多路IO接口上时,Libevent也采用了这种方式,不过还是有点差别的。
相关结构体:
现在来看一下event_base结构体,下面代码只列出了本文要讲的内容:
- //event-internal.h文件
- structevent_base{
- conststructeventop*evsel;
- void*evbase;
- …
- };
- structeventop{
- constchar*name;//多路IO复用函数的名字
- void*(*init)(structevent_base*);
- int(*add)(structevent_base*,evutil_socket_tfd,shortold,shortevents,void*fdinfo);
- int(*del)(structevent_base*,void*fdinfo);
- int(*dispatch)(structevent_base*,structtimeval*);
- void(*dealloc)(structevent_base*);
- intneed_reinit;//是否要重新初始化
- //多路IO复用的特征。参考http://blog.csdn.net/luotuo44/article/details/38443569
- enumevent_method_featurefeatures;
- size_tfdinfo_len;//额外信息的长度。有些多路IO复用函数需要额外的信息
- };
//event-internal.h文件 struct event_base { const struct eventop *evsel; void *evbase; … }; struct eventop { const char *name; //多路IO复用函数的名字 void *(*init)(struct event_base *); int (*add)(struct event_base *,evutil_socket_t fd,short old,short events,void *fdinfo); int (*del)(struct event_base *,void *fdinfo); int (*dispatch)(struct event_base *,struct timeval *); void (*dealloc)(struct event_base *); int need_reinit; //是否要重新初始化 //多路IO复用的特征。参考http://blog.csdn.net/luotuo44/article/details/38443569 enum event_method_feature features; size_t fdinfo_len; //额外信息的长度。有些多路IO复用函数需要额外的信息 };
可以看到event_base结构体中有一个struct eventop类型指针。而这个struct eventop结构体的成员就是一些函数指针。名称也像一个多路IO复用函数应该有的操作:add可以添加fd,del可以删除一个fd,dispatch可以进入监听。明显只要给event_base的evsel成员赋值就能使用对应的多路IO复用函数了。
选择后端:
可供选择的后端:
现在来看一下有哪些可以用的多路IO复用函数。其实在Libevent的源码目录中,已经为每一个多路IO复用函数专门创建了一个文件,如select.c、poll.c、epoll.c、kqueue.c等。
打开这些文件就可以发现在文件的前面都会声明一些多路IO复用的操作函数,而且还会定义一个struct eventop类型的全局变量。如下面代码所示:
- //select.c文件
- staticvoid*select_init(structevent_base*);
- staticintselect_add(structevent_base*,int,void*);
- staticintselect_del(structevent_base*,void*);
- staticintselect_dispatch(structevent_base*,structtimeval*);
- staticvoidselect_dealloc(structevent_base*);
- conststructeventopselectops={
- "select",
- select_init,
- select_add,
- select_del,
- select_dispatch,
- select_dealloc,
- 0,/*doesn'tneedreinit.*/
- EV_FEATURE_FDS,
- };
- //poll.c文件
- staticvoid*poll_init(structevent_base*);
- staticintpoll_add(structevent_base*,void*_idx);
- staticintpoll_del(structevent_base*,void*_idx);
- staticintpoll_dispatch(structevent_base*,structtimeval*);
- staticvoidpoll_dealloc(structevent_base*);
- conststructeventoppollops={
- "poll",
- poll_init,
- poll_add,
- poll_del,
- poll_dispatch,
- poll_dealloc,
- 0,/*doesn'tneed_reinit*/
- EV_FEATURE_FDS,
- sizeof(structpollidx),
- };